Professional Documents
Culture Documents
Restlet1.1 API
Restlet1.1 API
Table of Contents
1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12
1.1 Welcome to the Restlet Team ! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12 1.2 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12 1.3 Additional information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12 1.4 Usage scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13 1.4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13 1.4.2 Client and server side. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13 1.4.3 Servlet compatible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13 1.4.4 Complete Web server. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13 1.4.5 Technology agnostic. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13 1.5 Other Sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13
2.12 Migration guide from Restlet 1.0 to 1.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .20 2.12.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .20 2.12.2 Important breaking changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .20 2.12.2.1 Handling of context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .20 2.12.2.2 Sample code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21 2.12.3 Handling of resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21 2.12.4 Usage of the Servlet Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21 2.12.5 Accessing current objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22 2.12.6 Accessing the original resource's reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22 2.12.7 Handling of statuses and exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22 2.12.8 Miscellaneous. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22 2.12.9 Deprecations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23 2.12.9.1 Resource class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23 2.12.9.2 Variant class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23 2.12.9.3 TunnelService. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24 2.12.9.4 MetadataService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24 2.12.9.5 ConverterService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24 2.12.9.6 Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24 2.12.9.7 Response. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24 2.12.9.8 Finder. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24 2.12.9.9 Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25 2.12.9.10 Restlet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25 2.12.9.11 Form. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25 2.12.9.12 Status . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25 2.12.9.13 ChallengeScheme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25 2.12.9.14 Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25 2.12.9.15 Response . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25 2.12.9.16 Guard. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25 2.12.9.17 Context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26 2.12.9.18 TransformRepresentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26
4.5 Advanced request routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .42 4.5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .42 4.5.2 Default matching mode. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .42 4.5.3 Tuning the routing. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .42 4.6 Getting parameter values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .42 4.6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .42 4.6.2 Getting values from a web form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .42 4.6.3 Getting values from a query . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .43 4.6.4 Getting values from the cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .43 4.6.5 Extracting values from query, entity, cookies into the request's attributes . . . . .43
6.5 FileUpload extension. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .58 6.5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .58 6.5.2 Description. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .58 6.5.3 Usage example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .58 6.6 FreeMarker extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .60 6.6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .60 6.6.2 Description. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .60 6.7 Grizzly extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .61 6.7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .61 6.7.2 Description. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .61 6.8 HTTP Client extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .61 6.8.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .61 6.8.2 Description. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .61 6.9 JavaMail extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .62 6.9.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .62 6.9.2 Description. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .62 6.10 JAXB extension. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .62 6.10.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .62 6.10.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .62 6.11 JAX-RS extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .62 6.11.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .62 6.11.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .63 6.11.3 Create JAX-RS example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .63 6.11.3.1 Create a root resource class. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .63 6.11.3.2 Create ApplicationConfig . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .64 6.11.4 Set up a JAX-RS server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .64 6.11.4.1 Run in a Servlet Container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .65 6.12 JDBC extension. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .65 6.12.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .65 6.12.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .65 6.13 Jetty extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .66 6.13.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .66 6.13.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .66 6.13.3 Usage example. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .66 6.13.3.1 HTTPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .66 Restlet User Guide - Version 1.1 5
6.13.4 Embedding Jetty & AJP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .67 6.13.4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .67 6.13.4.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .67 6.14 JiBX extension. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .70 6.14.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .70 6.14.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .70 6.15 JSON extension. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .70 6.15.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .70 6.15.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .70 6.16 Net extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .71 6.16.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .71 6.16.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .71 6.17 OAuth extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .71 6.17.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .71 6.17.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .71 6.17.3 References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .71 6.18 Servlet extension. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72 6.18.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72 6.18.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72 6.19 Simple extension. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72 6.19.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72 6.19.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72 6.20 Spring extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72 6.20.1 Table of contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72 6.20.2 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73 6.20.3 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73 6.20.4 Spring extension - Integration modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73 6.20.4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73 6.20.4.2 Restlet as main container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73 6.20.4.3 Spring as main container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73 6.20.5 Spring extension - Configuring Restlet beans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .74 6.20.5.1 Passing the parent context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .74 6.20.6 Spring extension - A complete example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .75 6.20.6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .75 6.20.6.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .75 Restlet User Guide - Version 1.1 6
6.20.7 Spring extension - Configuration of Restlet Resources . . . . . . . . . . . . . . . . . . . . . .77 6.20.7.1 Configuration of basic properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .77 6.20.7.2 Configuration of representation templates . . . . . . . . . . . . . . . . . . . . . . . . . .78 6.21 SSL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .79 6.21.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .79 6.21.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .79 6.21.2.1 JsslutilsSslContextFactory. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .79 6.21.2.2 PkixSslContextFactory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .79 6.22 Velocity extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .80 6.22.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .80 6.22.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .80 6.23 WADL extension. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .81 6.23.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .81 6.23.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .81 6.23.2.1 Indicate schema relative to an XML representation . . . . . . . . . . . . . . . . .81 6.24 Oracle XDB Restlet Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .82 6.24.1 Documentation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .82 6.24.2 Using XDB Restlet Adapter within Maven projects . . . . . . . . . . . . . . . . . . . . . . . . .82 6.24.3 Oracle XDB Restlet Adapter - Architecture - Introduction . . . . . . . . . . . . . . . . . .82 6.24.3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .82 6.24.3.2 Architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .83 6.24.4 Oracle XDB Restlet Adapter - Installing. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .83 6.24.4.1 Installing Oracle XDB Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .83 6.24.5 Oracle XDB Restlet Adapter - Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .84 6.24.5.1 Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .84 6.24.5.2 Minimalistic test comparing REST versus native SOAP. . . . . . . . . . . . .84 6.24.6 Oracle XDB Restlet Adapter - FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .90 6.24.6.1 Where Restlet logging information goes? . . . . . . . . . . . . . . . . . . . . . . . . . . .90 6.24.6.2 How many concurrent session are started by Oracle?. . . . . . . . . . . . . . . .91 6.24.6.3 Which is the effective Oracle user when run a REST WS? . . . . . . . . . .91 6.24.6.4 How to enable anonymous REST WS? . . . . . . . . . . . . . . . . . . . . . . . . . . . . .91 6.24.6.5 How can I define my Application in XdbServerServlet?. . . . . . . . . . . . .92 6.24.7 Oracle XDB Restlet Adapter - Others . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .93 6.24.7.1 Future plans. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .93 6.24.7.2 Known caveats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .93 Restlet User Guide - Version 1.1 7
6.24.7.3 Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .93 6.24.8 XMLDB Restet Adapter/Lucene/Maven . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .93 6.24.8.1 Purpose of the document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .93 6.24.8.2 Change Log . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .94 6.24.8.3 Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .94 6.24.8.4 Where to download . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .94 6.24.8.5 Directory structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .94 6.24.8.6 Configuration Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .95 6.24.8.7 Targets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .95 6.24.9 XMLDB Restet Adapter/Lucene/Maven - Running/Testing . . . . . . . . . . . . . . . . .96 6.24.9.1 Starting Jetty to debug these services outside OJVM . . . . . . . . . . . . . . . .96 6.24.9.2 Testing with telnet. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .97 6.24.9.3 Testing with JMeter plugin for Maven . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .98 6.24.9.4 Measuring performance using Apache JMeter . . . . . . . . . . . . . . . . . . . . . .99 6.24.10 XMLDB Restet Adapter/Lucene/Maven - Todo List . . . . . . . . . . . . . . . . . . . . . 100 6.24.10.1 ToDo list. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 6.24.11 XMLDB Restet Adapter/Lucene/Maven - Services implemented . . . . . . . . 100 6.24.11.1 Services implemented. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
7.6 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 7.6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 7.6.1.1 Zip content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 7.6.2 Description. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 7.6.2.1 GWT page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 7.6.2.2 Server side . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 7.7 Authenticating requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 7.7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 7.7.2 Authentication with the HTTP_BASIC scheme . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 7.7.3 Authentication with the HTTP_DIGEST scheme. . . . . . . . . . . . . . . . . . . . . . . . . . . 112 7.8 Working with JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 7.8.1 Description. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 7.9 Working with XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 7.9.1 Description. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
9 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
9.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 9.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 9.3 Restlet.org Web server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 9.3.1 Table of contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 9.3.2 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 9.3.3 Imported classes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 9.3.4 Declaring the Main class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 9.3.5 Main method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 9.3.6 Build the component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 9.3.7 Redirection Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 9.3.8 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 9.4 REST Web Services book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 9.4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
10 Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
10.1 Table of contents. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 10.2 Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 10.3 Client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 10.4 Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 10.5 Connector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 10.6 Context 10.8 Engine 10.9 Filter 10.10 Finder 10.11 Guard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 10.7 Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
10.12 Redirector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 10.13 Representation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 10.14 Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 10.15 Resource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 10.16 Response . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Restlet User Guide - Version 1.1 10
10.17 Restlet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 10.18 Route 10.20 Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 10.19 Router . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 10.21 Transformer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 10.22 Uniform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 10.23 Virtual Host . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
11
1 Introduction
1.2 Overview
Restlet is a lightweight REST framework for Java that lets you embrace the architecture of the Web and benefit from its simplicity and scalability. By leveraging our innovative REST engine, you can start blending your Web Sites and Web Services into uniform Web Applications! Restlet has a light core but thanks to its pluggable extension, it is also a comprehensive REST framework for Java. It supports all REST concepts (Resource, Representation, Connector, Component, etc.) and is suitable for both client and server Web applications. It supports major Web standards like HTTP, SMTP, XML, JSON, WADL, and Atom. Many extensions are also available to integrate with Servlet, Spring, Jetty, Grizzly, Simple, JAXB, JAX-RS, JiBX, Velocity, or FreeMarker. A GWT version is also available and is a direct port of the main Java version.
Roadmap6, with related links to our issue tracker Team7, listing core committers, extension committers and all contributors Legal terms8, important information about our licensing scheme and the registered Restlet trademark Acknowledgments9, to give credits to important software or organizations we rely on
2. 3. 4.
On REST.org11 (REST search engine and blog) Noelios.com12 (technical support, commercial licenses, services, etc.) More REST related resources13
Notes
1. 2. 3. 4. 5. 6. 7. 8. 9. http://www.restlet.org/about/team http://www.restlet.org/about/introduction http://www.restlet.org/about/features http://www.restlet.org/about/quotes http://www.restlet.org/about/faq http://www.restlet.org/about/roadmap http://www.restlet.org/about/team http://www.restlet.org/about/legal http://www.restlet.org/about/acknowledgments
14
2 What's new
2.1 Introduction
After one year and half of development, the Restlet project has made tremendous progress. We will try to summarize here the main benefits that you can expect by migrating from Restlet 1.0 to the latest 1.1 version.
In order to deal with your largest development needs, support for application modularization has been added. It is now easy to split a large application into several ones, and still be able to efficiently communicate. There is a new internal protocol (RIAP) to do private RESTful calls between applications hosted in the same JVM.
Google Web Toolkit (Restlet-GWT module for Rich Web Clients) JAIN/SLEE
Most of the time, your Restlet Applications code will be fully portable, requiring only simple deployment configuration adjustments. Regarding configuration, we now support our own compact XML syntax. This can be very convenient, in addition to the usual programmatic way, to let administrators tweak the configuration of Restlet components, connectors and virtual hosts, without recompiling the source code. This is also possible to leverage Spring XML configuration mechanism to similar results.
New TaskService to execute synchronous or asynchronous tasks using a thread pool whose life cycle is automatically managed by the application. Representation digests (MD5 and more) are now supported to ensure the integrity of data exchanged between clients and servers. HTTP DIGEST authentication (client and server side) is now supported and leverages the new authentication pluggability added to the engine. The logging facility has also been fully refactored to be more consistency and better organized.
2.9 Connectors
Built-in HTTP client and server connectors were added right inside the Restlet Engine, with zero external dependency and a performance close to other connectors. This is the recommended choice during development phases. For production, we still recommend using our more robust Jetty connector. Powerful HTTP server connector based on Suns Grizzly NIO framework was added. It is the first to leverage the end-to-end NIO capacities of the Restlet API. For example, it allows direct transfer from files to sockets, reducing JVM memory usage and CPU consumption! Overall SSL support was greatly enhanced with access to new attributes for all HTTP connectors and with the addition of a new com.noelios.restlet.ext.ssl extension based on the jSSLutils library. New POP3 client connector based on JavaMail was added. It complements the existing SMTP client connector to allow Restlet applications to conveniently retrieve and send emails. The development was sponsored by RunMyProcess SAS. Partial GETs and PUTs are now supported by the FILE client connector. In addition with the new RangeService and Range classes, it now offers full and transparent support for HTTP content ranges, enabling important features such as partial retrievals and resumable uploads. The AsyncWeb HTTP server connector was removed. The AsyncWeb is currently being integrated with MINA, the NIO framework from Apache. We will introduce support for MINA in Restlet 1.2. But for Restlet 1.1, it didn't make sense to continue the support for AsyncWeb. The Jetty 5 HTTP server connector was removed and is replaced by the Jetty 6 connector which is now fully stable.
18
2.10 Extensions
Full support for WADL, a popular description language for RESTful application. It can be used to configure components, applications and resources. In addition, existing Restlet applications can be enhanced to dynamically expose a REST API documentation as either a raw WADL XML document or as a converted HTML document. This magic documentation feature, fully customizable, works by introspecting application resources and using an HTML template provided by Yahoo! Several features were sponsored by NetDev Ltd. New JAXB extension for easy XML to POJO mappings. JAXB is a standard annotation-based API. New JiBX extension providing an efficient and flexible alternative to JAXB for XML to object serialization. New Spring extension to provide even more integration possibilities with Spring, Servlet and Restlet at the same time. The existing Spring API extension has also been improved based on user feed-back and contributions. Atom extension has been updated to conform to the latest Atom Publishing Protocol specifications. The extension now allows both the retrieval and the writing of APP service documents and Atom feeds. Extensive implementation of the JAX-RS 1.0 API (developed by JSR-311) was contributed by Stephan Koops. We are now waiting for access to the TCK for verification of completeness. New OAuth extension was contributed by Adam Rosien, leveraging a new pluggable authentication scheme. OAuth is a standard related to OpenID for securing API authorization. It is typically used as secure way for people to give an application access to their data. New XDB extension providing integration with Oracle embedded JVM contributed by Marcelo Ochoa. New Restlet-GWT module provided as a port of the Restlet client API to the Google Web Toolkit 1.5 AJAX platform. This module also supports HTTP authentication.
2.11 Misc
Added new licensing options. You can now choose between either CDDL 1.0 or LGPL 2.1 or LGPL 3.0 depending on your project constraints. Commercial licenses can also be purchased from Noelios Technologies via our online process. Restlet JARs are now fully usable OSGi bundles. This allows you to deploy Restlet application in OSGi environments such as Eclipse Equinox of Apache Felix. 19
Thus, we encourage you to override the default Application() constructor instead of the Application(Context) one which is only useful in a few cases where you need to immediately have access to the application's context. Another consequence is that parameters or attributes are not copied from the component to the application by the default implementation of the Context#createChildContext() method which is typically used to prepare the Application's context based on the parent Component's context.
20
2.12.2.2 Sample code When a component instantiate an Application, or any kind of Restlet, it is no more mandatory to specify the context. Taking a simple component that attaches an application, here is the ancient way to achieve this:
Component component = new Component(); // Add a new HTTP server listening on port 8182. component.getServers().add(Protocol.HTTP, 8182); // Attach the sample application. component.getDefaultHost().attach(new FirstStepsApplication(component.getContext()));
If you still need to handle the context in the Application constructor, you must do as follow:
Component component = new Component(); // Add a new HTTP server listening on port 8182. component.getServers().add(Protocol.HTTP, 8182); // Attach the sample application. component.getDefaultHost().attach(new FirstStepsApplication(component.getContext().createChildContext()));
The application is instantiated with a child context, not the component context. Otherwise, your application might not start properly and a log trace will warn you.
21
A static ServletCall.getRequest(Request) method has been added to the Servlet extension and gives access to the HttpServletRequest object. The underlying component can now be customized which allows to define several applications either with a "/WEB-INF/restlet.xml file", or a "org.restlet.component" parameter in the "web.xml". see ServerServlet javadocs2 for more details.
These methods may help you to reduce the number of lines of code but, for proper object-oriented design, we recommend using them only under duress. Typical case is when you need to integrate Restlet code with a third-party library that doesn't let you pass in your Restlet context or objects. For example, you should by default prefer obtaining the current context using methods such as Restlet.getContext()3 or Handler.getContext()4.
2.12.8 Miscellaneous
This section lists several updates that may have an impact on your existing code
22
The Resource class now accepts POST requests without any entity, or with an empty entity. The list of known media-types defined on the MetadataService has been completed with Tomcat's entries Added a Representation.release() to have an uniform way to release a representation without forcing a read for example or manually closing the socket, the channel, the file, etc. Added a Representation.exhaust() method that reads and discards content optimally (better than getText()) Application is now concrete and has a setRoot() method. Filter.beforeHandle() and doHandle() methods can now indicate if the processing should continue normal, go to the afterHandle() method directly or stop immediately. IMPORTANT NOTE: as it isn't possible to add a return parameter to an existing method, the change can break existing filters. In this case, you just need to return the "CONTINUE" constant from your method and use "int" as a return parameter. Added Handler.getQuery() method to easily return the request's target resource reference query as a parsed form (series of parameters). The Message's getEntityAsDom(), getEntityAsSax() and getEntityAsForm() are now caching the result representation for easier reuse in a Restlet filters chain.
2.12.9 Deprecations
2.12.9.1 Resource class List of renamed methods to prevent confusion with lower-level methods handleGet(), handletPost(), handlePut() and handleDelete() now part of the parent class of Resource, the Handler class. Method getPreferredRepresentation() getRepresentation(Variant) post(Representation) put(Representation) delete() 2.12.9.2 Variant class Some properties and methods have been moved to the Representation subclass UNKNOWN_SIZE getExpirationDate, setExpirationDate getModificationDate, setModificationDate getSize, setSize getTag, setTag Replacement represent() represent(Variant) acceptRepresentation(Representation) storeRepresentation(Representation) removeRepresentations()
23
2.12.9.3 TunnelService List of renamed methods. Method getCharacterSetAttribute setCharacterSetAttribute getEncodingAttribute setEncodingAttribute getLanguageAttribute setLanguageAttribute getMediaTypeAttribute setMediaTypeAttribute 2.12.9.4 MetadataService This class allows to link a metadata with several extensions name. However, only the first one in the list will be returned by the getExtension(Metadata), it is considered as the preferred one. The "getMappings" and "setMappings" methods have been removed. Instead, use getExtension(Metadata), getMetadata(String) and the addExtension(String, Metadata), addExtension(String, Metadata, boolean preferred), clearExtension methods 2.12.9.5 ConverterService Since 1.1 with no replacement as it doesn't fit well with content negotiation. Most users prefer to handle those conversion in Resource subclasses. 2.12.9.6 Request As a consequence of the previous change, the following methods are not replaced: Request#getEntityAsObject, Request#setEntity(Object) 2.12.9.7 Response List of renamed methods. Method getChallengeRequest getRedirectRef setRedirectRef 2.12.9.8 Finder Method createResource(Request, Response) Replacement createTarget(Request, Response) and take care of the targetClass property. 24 Replacement getChallengeRequests getLocationRef setLocationRef Replacement getCharacterSetParameter setCharacterSetParameter getEncodingParameter setEncodingParameter getLanguageParameter setLanguageParameter getMediaTypeParameter setMediaTypeParameter
2.12.9.9 Template Removed the Logger parameter to all constructors. which still can be set with the setLogger(Logger) method. 2.12.9.10 Restlet The init(Request, Response) method is removed. Instead, make sure that you call the {@link #handle(Request, Response)} method from your Restlet superclass. 2.12.9.11 Form Removed the Logger parameter to all constructors. 2.12.9.12 Status Method isInfo(int code) isInfo() 2.12.9.13 ChallengeScheme ChallengeScheme HTTP_AWS replaced by HTTP_AWS_S3 2.12.9.14 Protocol The SMTP_STARTTLS protocol is removed. Use the "startTls" parameter on the JavaMail connector instead. 2.12.9.15 Response Method getChallengeRequest getRedirectRef setRedirectRef 2.12.9.16 Guard List of renamed methods. Method challenge(Response) Replacement challenge(Response, boolean) The added boolean indicates if the new challenge is due to a stale response. checkSecret(Request, String, char[]) Added the request parameter Replacement getChallengeRequests getLocationRef setLocationRef Replacement isInformational(int) isInformational()
checkSecret(String, char[])
25
2.12.9.17 Context List of renamed method. Method getDispatcher Replacement getClientDispatcher NB: it exists a server dispatcher.
Notes
1. 2. 3. 4. http://www.noelios.com/products/restlet-engine http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/servlet/ServerServlet.html http://www.restlet.org/documentation/snapshot/api/org/restlet/Restlet.html#getContext%28%29 http://www.restlet.org/documentation/snapshot/api/org/restlet/Handler.html#getContext%28%29
26
3 Getting started
We recommend that you consult the documentation available on the Restlet Web site1 to get you started. You will find a screencast, first steps and more detailed tutorial.
Notes
1. 2. 3. 4. http://www.restlet.org/documentation/1.1/ http://maven.apache.org/ http://www.restlet.org/downloads/maven http://www.restlet.org/documentation/1.1/faq#21
27
4 Restlet API
This chapter presents the Restlet API. It is a small set of packages, with classes, interfaces and enumerations that together provide a framework. This framework will guide you on the path to RESTful design and development. But be aware that you still need to understand REST in order to fully take advantage of the Restlet features1. For this purpose, we recommend the book "RESTful Web Services"2 from O'Reilly. We even wrote a part of it covering Restlet usage. For a more detailed presentation of the API, we recommend that you have a close look at the Restlet Tutorial3 and at the Javadocs of the API4, both available on the Restlet Web site.
request.clientInfo.acceptedMe The list of media-types diaTypes accepted by the client. request.clientInfo.acceptedCha The list of character sets racterSets accepted by the client. request.clientInfo.acceptedEnc The list of encodings accepted odings by the client. 28
request.clientInfo.acceptedLan The list of languages accepted guages by the client. [connector level] response.allowedMethods Allows the server to indicate its support for range requests Support for caching planned for Restlet 1.212 For "Handler" subclasses (such as Resource), a dynamic search is made that looks for the "allow*" methods declared on the class and that return "True". Non standard HTTP header. Credentials that contain the authentication information of the user agent for the realm of the resource being requested. Support for caching planned for Restlet 1.217 Set to "close" according to the server or client connector property (serverKeepAlive or clientKeepAlive).
Authentication-Info14 Authorization15
request.challengeResponse
Cache-Control16 Connection18
[connector level]
Content-Disposition19
message.entity.downloadName If the download name is not null, the header value is "attachment; filename=< entity.downloadName>". entity.encodings Indicates what additional content codings have been applied to the entity-body. Describes the natural language(s) of the intended audience for the enclosed entity. The size of the entity-body, in decimal number of OCTETs. Indicates the resource location for the entity enclosed in the message. Value and algorithm name of the digest associated to a representation. Indicates where in the full entity-body the partial body should be applied 29
Content-Encoding20
Content-Language21
entity.languages
Content-Length22 Content-Location23
entity.size entity.identifier
Content-MD524
representation.digest
Content-Range25
entity.range
entity.mediaType and entity.characterSet request.cookies current date entity.tag entity.expirationDate request.resourceRef (domain and port) request.conditions.match
Indicates the media type of the entity-body. List of one or more cookies sent by the client to the server. The date and time at which the message was originated. The current value of the entity tag for the requested variant. Support for expect header planned for Restlet 1.231 The date/time after which the response is considered stale. Support for misc headers planned for later34 Specifies the Internet host and port number of the resource being requested. Used with a method to make it conditional.
request.conditions.modifiedSin Used with a method to make it ce conditional. request.conditions.noneMatch Used with a method to make it conditional. Support planned for Restlet 1.240
request.conditions.unmodified Used with a method to make it Since conditional. entity.modificationDate Indicates the date and time at which the origin server believes the variant was last modified. Used to redirect the recipient to a location other than the Request-URI for completion of the request or identification of a new resource. Support for proxies planned for later45 Support for caching planned for Restlet 1.247 Support for proxies planned for later49 Support for proxies planned for later51 30
Location43
response.locationRef
Range52 Referer53
request.ranges request.refererRef
List one or more ranges to return from the entity The address (URI) of the resource from which the Request-URI was obtained. Support for misc headers planned for later55 Information about the software used by the origin server to handle the request. List of one or more cookies sent by the server to the client. List of one or more cookies sent by the server to the client. Not supported yet Support for misc headers planned for later61 Valuated to "chunked" if the entity is not null and its size is unknown (Representation.UNKNOWN_ SIZE) Support for misc headers planned for later64 Information about the user agent originating the request. Indicates the set of request-header fields that fully determines, while the response is fresh, whether a cache is permitted to use the response to reply to a subsequent request without revalidation. Support for proxies planned for later68 Support for caching planned for Restlet 1.270 Indicates the authentication scheme(s) and parameters applicable to the Request-URI. The list of client IP addresses, including intermediary proxies.
Retry-After54 Server56
response.serverInfo.agent
request.clientInfo.agent response.dimensions
response.challengeRequests
X-Forwarded-For
request.clientInfo.addresses
31
X-HTTP-Method-Override
Support for method tunnelling via header planned for Restlet 1.272
4.1.3 Appendix
Registry73 of headers74 maintained by IANA. Regsitry of HTTP status codes75 maintained by IANA.
4.2.3 Configuration
Each connector looks for its configuration from its context. The latter provides a list of modifiable parameters, which is the right place to set up the connector's configuration. Some parameters are defined by the NRE engine and thus are shared by all clients (in the ClientHelper hierarchy) and server connectors (in the ServerHelper hierarchy), and most of them by the connector's ClientHelper or ServerHelper subclasses. The list of all parameters are available in the javadocs. Pleaser refer to the rest of this document for references to these documentation. 4.2.3.1 Server connectors Here are the commons parameters78 dedicated to HTTP server connectors. Here is a sample code showing how to set such a parameter.
32
// Creating a minimal Restlet returning "Hello World" Restlet restlet = new Restlet() { @Override public void handle(Request request, Response response) { response.setEntity("Hello World!", MediaType.TEXT_PLAIN); } }; // Create the HTTP server and listen on port 8182 Server server = new Server(Protocol.HTTP, 8182, restlet); server.getContext().getParameters().add("useForwardedForHeader", "true"); server.start();
4.2.3.2 Client connectors Here are the commons parameters79 dedicated to HTTP client connectors. Here is a sample code showing how to set such a parameter.
Client client = new Client(Protocol.HTTP); client.getContext().getParameters().add("converter", "com.noelios.restlet.http.HttpClientConverter");
33
2.
3.
SSL client authentication is not configured as part of the SSL context, although the trust store and which peer certificates to trust are. Restlet User Guide - Version 1.1 34
4.3.1.2 Authentication In Restlet, authentication and authorization are handled very differently than in the Servlet world. Here you have full control of the process, no external XML descriptor is necessary. The default approach is to use the org.restlet.Guard class (a Restlet filter) or a subclass of it. By default, this class uses a map to store the login/password couples but this can be customized by overriding the "authenticate(Request)" method. From an org.restlet.data.Request, the login/password can be retrieved using these methods: - Request.getChallengeResponse().getIdentifier() : String // LOGIN - Request.getChallengeResponse().getSecret() : String // PASSWORD The HTTP server connectors currently only support HTTP BASIC authentication (the most widely used).
4.3.1.2.1 SSL client authentication
To enable client-side SSL authentication on an HTTPS server connector, set the wantClientAuthentication or needClientAuthentication parameters to true (in the first case, presenting a client certificate will be optional). The chain of client certificate is then accessible as List of X509Certificates in the org.restlet.https.clientCertificates Request attribute. 4.3.1.3 Coarsed grained authorization For the authorizations that are common to a set of resources, a Guard subclass can also be used by overriding the "authorize(Request)" method. Note that this method accepts all authenticated requests by default. You can plugin in your own mechanism here, like an access to a LDAP repository. 4.3.1.4 Fine grained authorization If the permissions are very fine grained, the authorizations should probably handled at the resource level directly instead of the Guard filter level (unless you want to put a filter in front of each resource). With the approach, you can make your permission depend on the value of the target resource on the resource and specific method invoked, etc.
4.3.2 Actors
4.3.2.1 Restlet API
4.3.2.1.1 ChallengeRequest
Contains information about the authentication challenge that is sent by an origin server to a client. For server-side Restlet applications, this object will typically be created and set on the current Response by a Guard added to the request processing chain. Then, when the response goes back to the Restlet engine, the server connector and the matching authentication helper will format it into the proper protocol artifact such as a "WWW-Authenticate" header in HTTP. For client-side Restlet applications, this object will typically be received in response to a request to a target resource requiring authentication. In HTTP, this is signalled by a 401 (Unauthorized) status. This means that a new request must be sent to the server with a valid challenge response Restlet User Guide - Version 1.1 35
set for the required challenge scheme. The client connector and matching AuthenticationHelper are responsible for parsing the protocol artifact such as the "WWW-Authenticate" header in HTTP.
4.3.2.1.2 ChallengeResponse
Contains information about the authentication challenge response sent by a client to an origin server. For server-side Restlet applications, this object will typically be created by the server connector with the help from the matching AuthenticationHelper for parsing. For client-side Restlet applications, this object must be manually created before invoking the context's client dispatcher for example.
4.3.2.1.3 ChallengeScheme
Indicates the challenge scheme used to authenticate remote clients. This only identifies the scheme used or to be used but doesn't contain the actual logic needed to handle the scheme. This is the role of the AuthenticatorHelper subclasses.
4.3.2.1.4 Guard
This is a Restlet Filter that guards the Restlets or Resources attached to it from unauthenticated and/or unauthorized requests. 1. When a request reaches it, it first attempts to authenticate it, i.e. to make sure that the challenge scheme used is supported and that the credentials given by the client (such as a login and password) are valid. The actual implementation of the authentication is delegated to the matching authentication helper. The result of this authentication can be: 1. Valid: the authentication credentials are valid, the right scheme was used and the credentials could be verified by calling back the checkSecret() method on Guard. Here are the next steps 1. The authorize() method is called and if authorization is given the accept() method is invoked, which delegates to the attached Restlet or Resource by default. Otherwise, the forbid method is called, which sets the response status to CLIENT_ERROR_FORBIDDEN (403).
3. 4.
5.
Missing: no credentials could be found, the challenge() method is invoked which delegates to the matching authenticator helper. Invalid: bad credentials were given such as a wrong password or unsupported scheme was used. If the "rechallenge" property is true, the challenge() method is invoked otherwise, the forbid() method is invoked. Stale: the credentials expired and must be renew. Therefore, the challenge() method is invoked.
36
4.3.2.2 Noelios Restlet Engine Most of the logic related to authentication is located in the package "com.noelios.restlet.authentication".
4.3.2.2.1 AuthenticationUtils
Static utilities methods to parse HTTP headers, find the matching authentication helper and misc methods.
4.3.2.2.2 AuthenticationHelper
Base class for authentication helpers. There are also subclasses for the schemes internally supported by the NRE : HTTP Basic, HTTP Digest, HTTP Amazon S3 (client) and SMTP Plain. 4.3.2.3 Extensions In addition to the internal authentication helpers, additional schemes can be supported using pluggable extensions. Currently, there is an extension available for the HTTP OAuth scheme.
4.3.3 Authentication
4.3.3.1 Introduction There are two commons ways to authenticate your users with your Restlet application. The first is to use is to leverage the standard HTTP authentication mechanism, either the Basic or the Digest authentication. The Basic mechanism is sending the password in clear and should only be used over a secure HTTPS channel. The second mechanism is to use a custom authentication form and some cookie set by the server. 4.3.3.2 HTTP Basic authentication
4.3.3.2.1 Introduction
Here is a very simple code illustrating a component that guards its applications with the DIGEST authentication scheme. The whole code can be downloaded here (page 0).
4.3.3.2.2 Description of the server side
4.3.3.2.2.1 Component
The sample component is composed of two parts. The first one is a very simple Restlet that answers to request with a "hello, word" text representation. Of course this Restlet is a very simple representation of your own complex application.
// Restlet that simply replies to requests with an "hello, world" text message Restlet restlet = new Restlet() { @Override public void handle(Request request, Response response) {
37
Then, the component protects this Restlet with a Guard instance based on the BASIC authentication scheme. Once the instance is created, it is given the list of known (login/password) pairs via the "secrets" attibute.
// Guard the restlet with BASIC authentication. // Use the basic guard Guard guard = new Guard(component.getContext().createChildContext(), ChallengeScheme.HTTP_BASIC, "Sample application."); // Load a single static login/secret pair. guard.getSecrets().put("login", "secret".toCharArray()); guard.setNext(restlet); component.getDefaultHost().attachDefault(guard);
4.3.3.2.2.2 Customization
The authentication and authorization decisions are fully customizable via the authenticate() and authorize() methods of the Guard class. Any custom mechanism can be used to check whether the given credentials are valid and whether the authenticated user is authorized to continue to the attached Restlet.
4.3.3.2.2.3 Description of the client side
The credentials are transmitted to the request via a ChallengeResponse object as follow:
Reference reference = new Reference("http://localhost:8182/"); Client client = new Client(Protocol.HTTP); Request request = new Request(Method.GET, reference); // Send an authenticated request using the Basic authentication scheme. ChallengeResponse authentication = new ChallengeResponse(ChallengeScheme.HTTP_BASIC, "login", "secret"); request.setChallengeResponse(authentication); // Send the request Response response = client.handle(request); // Should be 200 System.out.println(response.getStatus());
Here is a very simple code illustrating a component that guards its applications with the DIGEST authentication scheme. The whole code can be downloaded here83.
38
The sample component is composed of two parts. The first one is a very simple Restlet that answers to request with a "hello, word" text representation. Of course this Restlet is a very simple representation of your own complex application.
// Restlet that simply replies to requests with an "hello, world" text message Restlet restlet = new Restlet() { @Override public void handle(Request request, Response response) { response.setEntity(new StringRepresentation("hello, world", MediaType.TEXT_PLAIN)); } };
Then, the component protects this Restlet with a Guard instance based on the DIGEST auth entication scheme. A dedicated constructor of the Guard class of the Restlet API allows you to create such instance. Once the instance is created, it is given the list of known (login/password) pairs via the "secrets" attibute.
// Guard the restlet with DIGEST authentication. Collection<String> baseUris = new ArrayList<String>(); // Use the basic guard Guard guard = new Guard(component.getContext().createChildContext(), "realm", baseUris, "serverKey"); // Load a single static login/secret pair. guard.getSecrets().put("login", "secret".toCharArray()); guard.setNext(restlet); component.getDefaultHost().attachDefault(guard);
4.3.3.3.2.2 Customization
As you may have noticed earlier, the list of known login/password pairs are loaded by the basic Guard via the "secrets" attribute. This is useful when the list of pairs are known by advance and is not susceptible to change. In a more realistic case, the credentials are hosted in a database or a LDAP directory, etc. In this case, the responsibility to resolve the password according to the login is deported to a dedicated sub class of the org.restlet.util.Resolver. An instance of this sub class will be finally passed to the Guard as follow:
// Guard the restlet with DIGEST authentication. Collection<String> baseUris = new ArrayList<String>(); // Use the basic guard Guard guard = new Guard(component.getContext().createChildContext(), "realm", baseUris, "serverKey"); // Use the customized resolver guard.setSecretResolver(new TestResolver()); guard.setNext(restlet); component.getDefaultHost().attachDefault(guard);
The contract of the Resolver is a simple method which aims at returning the given password according to the given login: Restlet User Guide - Version 1.1 39
import org.restlet.util.Resolver; /** * Customized resolver. */ public class TestResolver extends Resolver<char[]> { /** * Returns the value that corresponds to the given name. */ @Override public char[] resolve(String name) { // Could have a look into a database, LDAP directory, etc. if ("login".equals(name)) { return "secret".toCharArray(); } return null; } }
The authentication with the DIGEST scheme is bit more difficult than the one for the BASIC scheme. The credentials provided by the client is the result of computation of data given by the client on one side (login and password) and by the server on the other side ("nonce" value, "realm" value, etc.). Unless these pieces of data are known in advance by the client, it appears that in general a first request is required in order to collect them.
Reference reference = new Reference("http://localhost:8182/"); Client client = new Client(Protocol.HTTP); Request request = new Request(Method.GET, reference); // Create the Challenge response used by the client to authenticate its requests. ChallengeResponse challengeResponse = new ChallengeResponse(ChallengeScheme.HTTP_DIGEST, "login", "secret"); request.setChallengeResponse(challengeResponse); // Send the first request Response response = client.handle(request); // Should be 401, since the client needs some data sent by the server in // order to complete the ChallengeResponse. System.out.println(response.getStatus());
Then, the second step allows to get the required data for the final computation:
// Complete the challengeResponse object according to the server's data Form form = new Form(); form.add("username", "login"); form.add("uri", reference.getPath()); // Loop over the challengeRequest objects sent by the server. for (ChallengeRequest challengeRequest : response.getChallengeRequests()) { // Get the data from the server's response. if (ChallengeScheme.HTTP_DIGEST.equals(challengeRequest.getScheme())) { Series<Parameter> params = challengeRequest.getParameters(); form.add(params.getFirst("nonce")); form.add(params.getFirst("realm")); form.add(params.getFirst("domain")); form.add(params.getFirst("algorithm")); form.add(params.getFirst("qop")); } }
Then, we compute the data into the final digested value: Restlet User Guide - Version 1.1 40
// Compute the required data String a1 = Engine.getInstance().toMd5("login" + ":" + form.getFirstValue("realm") + ":" + "secret"); String a2 = Engine.getInstance().toMd5(request.getMethod() + ":" + form.getFirstValue("uri")); form.add("response", Engine.getInstance().toMd5(a1 + ":" + form.getFirstValue("nonce") + ":" + a2)); challengeResponse.setCredentialComponents(form);
4.3.4 Authorization
4.3.4.1 Description By default, the Guard class autorizes all the sucessfully authenticated requests to go to the next Restlet attached to it. However it is very easy to change this behavior to introduce any sort of authorization mechanism. The method to override is Guard#authorize(Request84 request) which returns true by default.
4.4.2 Description
The basic idea is that from a Restlet point of view, your application with be composed of resources, extending the org.restlet.resource.Resource class. Those subclassed will be in charge of handling the incoming requests. One instance of your resource subclass will be created for each request to handle, making sure that you don't have to care about concurrent access at this point of your application. When you resource is instantiated, it will need to expose its representations (via HEAD, GET methods), to store (PUT method), accept (POST method) or remove (DELETE method) representations. During construction, based on the actual identity of your resource and other parameters or attributes of the request, you will be able to contact your persistence backend in order to support your processing logic or the representations of your resources returned.
41
42
4.6.5 Extracting values from query, entity, cookies into the request's attributes
When routing URIs to Resource instances or Restlet, you can decide to transfer data from query, entity or cookies into the request's list of attributes. This mechanism is declarative and has been implemented at the level of the "routes" (see the code below for more information). This mechanism transfers data from the query (method "extractQuery"), the entity (method "extractEntity") or the Cookies (method "extractCookies") to the request's list of parameters. For example, when implementing your Application, assuming that the posted web form contains a select input field (called "selectField") and a text field ( called "textField"). If you want to transfer them respectively to attributes named "selectAttribute" and "textAttribute", just proceed as follow.
@Override public Restlet createRoot() { Router router = new Router(getContext()); Route route = router.attachDefault(MyResource.class); route.extractEntity("selectAttribute", "selectField", true); route.extractEntity("textAttribute", "textField", false); return router; }
You will get a String value in the "selectAttribute" (the selected option), and a Form object which is a collection of key/value pairs (key="textField" in this case) with the "textAttribute" attribute. Here is sample code which helps to retrieve some attributes:
// Get the map of request attributes Map<String, Object> map = request.getAttributes(); // Retrieve the "selectAttribute" value String stringValue = (String) map.get("selectAttribute"); System.out.println(" value => " + stringValue); // Retrieve the "textAttribute" collection of parameters Object object = map.get("textAttribute"); if(object != null){ if(object instanceof Form){ Form form = (Form) object;
43
for (Parameter parameter : form) { System.out.print("parameter " + parameter.getName()); System.out.println("/ " + parameter.getValue()); } } }
Notes
1. 2. 3. 4. 5. 6. 7. 8. 9. http://www.restlet.org/about/features http://www.restlet.org/documentation/books http://www.restlet.org/documentation/1.1/tutorial http://www.restlet.org/documentation/1.1/api/ http://www.restlet.org/documentation/1.1/api/org/restlet/data/Message.html#getAttributes() http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1 http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2 http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3 http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
10. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.5 11. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.6 12. http://restlet.tigris.org/issues/show_bug.cgi?id=213 13. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7 14. http://rfc.net/rfc2617.html#s3.2.3 15. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.8 16. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 17. http://restlet.tigris.org/issues/show_bug.cgi?id=213 18. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.10 19. http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1 20. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11 21. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.12 22. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13 23. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.14 24. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.15 25. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.15 26. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17 27. http://www.w3.org/Protocols/rfc2109/rfc2109 28. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18 29. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19 30. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.20 31. http://restlet.tigris.org/issues/show_bug.cgi?id=413 32. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21 33. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.22 34. http://restlet.tigris.org/issues/show_bug.cgi?id=282 35. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.23
44
36. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24 37. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25 38. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26 39. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.27 40. http://restlet.tigris.org/issues/show_bug.cgi?id=115 41. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.28 42. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1 43. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.30 44. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.31 45. http://restlet.tigris.org/issues/show_bug.cgi?id=207 46. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.32 47. http://restlet.tigris.org/issues/show_bug.cgi?id=213 48. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.33 49. http://restlet.tigris.org/issues/show_bug.cgi?id=207 50. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.34 51. http://restlet.tigris.org/issues/show_bug.cgi?id=207 52. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 53. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.36 54. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.37 55. http://restlet.tigris.org/issues/show_bug.cgi?id=282 56. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.38 57. http://www.w3.org/Protocols/rfc2109/rfc2109 58. http://www.ietf.org/rfc/rfc2965.txt 59. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.39 60. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.40 61. http://restlet.tigris.org/issues/show_bug.cgi?id=282 62. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.41 63. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.42 64. http://restlet.tigris.org/issues/show_bug.cgi?id=282 65. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43 66. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44 67. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.45 68. http://restlet.tigris.org/issues/show_bug.cgi?id=207 69. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.46 70. http://restlet.tigris.org/issues/show_bug.cgi?id=213 71. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.47 72. http://restlet.tigris.org/issues/show_bug.cgi?id=297 73. http://www.iana.org/assignments/message-headers/perm-headers.html 74. http://www.iana.org/assignments/message-headers/perm-headers.html 75. http://www.iana.org/assignments/http-status-codes 76. http://www.restlet.org/documentation/1.1/faq#04 77. http://www.restlet.org/documentation/1.1/faq#05
45
78. http://www.restlet.org/documentation/1.1/nre/com/noelios/restlet/http/HttpServerHelper 79. http://www.restlet.org/documentation/1.1/nre/com/noelios/restlet/http/HttpClientHelper 80. http://www.restlet.org/documentation/1.1/nre/com/noelios/restlet/util/SslContextFactory.html 81. http://www.restlet.org/documentation/1.1/nre/com/noelios/restlet/util/DefaultSslContextFactory.html#init(org.restlet.util.Seri es) 82. http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#SystemProps 83. http://wiki.restlet.org/docs_1.1/176-restlet 84. http://www.restlet.org/documentation/snapshot/api/org/restlet/data/Request.html
46
5 Restlet Engine
The engine is the set of classes that together supports or implements the Restlet API. Currently, there is a strict separation with the API, but this will change in Restlet 1.2 to facilitate the deployment and packaging of applications. This seperation will however stay conceptually between the classes that are expected to be used by Restlet users while developping their applications and the classes that are expected to be used by the Restlet core developers. Note that the engine is also extensible and can detect pluggable connectors available on the classpath as well as pluggable authentication helpers.
Note that those connectors available in the engine JAR but still need to be declared in your Restlet component, otherwise your applications won't be able to use them!
47
The riap protocol came to life as a solution for the issue 374 "Add support for pseudo protocols"4. Which in turn started of based from discussion on issue 371 "Optimize Internal Calls"5.
About riap.
The riap://... scheme identifies a so-called pseudo-protocol (terminologogy derived from Apache Cocoon pointing out the difference between 'real' or 'official'/ public protocols and this scheme which only relates to internal processing of the restlet system architecture. RIAP is short for 'Restlet Internal Access Protocol'. In short, it is just a mechanism that allows various applications to call upon each other to retrieve resources for further processing. "Application" here refers to the strict restlet API notion. Same remark should be made on the usage of "Component" further down. The riap:// scheme brings a URI-notation for these inter-application calls. With that URI-notation those calls fall naturally under appliance of the uniform interface. There are two blends of this riap protocol, that use distinct 'authorities' for different use cases. riap://component/**
48
riap://application/** resolves the remainder-URI with respect to the current context's "application" (so applications could use this scheme to call resources within themselves!)
Think about some application X that needs a resource Y that is available on a configurable base-uri. Whatever that baseUri is, the application-implementation should just use the context.getClientDispatcher() to get() that needed resource. So basically the dependency from application X to "whatever service that will offer me resource Y" can be expressed in this base-URI. Thinking about dependency injection solutions, the configuration of X is covered by calling some setResourceYBaseUri(...). That will cover any of these 'service-providers' of this resource Y: file://whateverpath/Y a local static file
riap://component/internalpath/Y a URI resolved versus the internal router of the current 'Component'
riap://application/fallback/Y this application itself providing some basic version of the required resource.
Next to this expression flexibility of dependencies, this riap:// approach ensures some extra efficiency: 1. 2. It avoids going through the actual network layers versus the alternative of calling http://localhost/publicpath/Y It offers direct access to the Response and Representation objects allowing to bypass possibly useless serialization-deserialization (e.g. for sax and or object representations)
shielding:
49
1.
It offers the possibility to keep the internal component offering resource Y to be available only internally (not publicly over http://hostname/publicpath/Y)
Bottom line: the basic idea behind this riap:// is one of flexibly decomposing your 'component' in smaller reusable/configurable/interchange-able 'applications' while assuring optimal efficiency when calling upon each other.
How to use.
Calling the riap:
To call a resource via the riap:// scheme one can just use:
Context context; context.getClientDispatcher().get("riap://component/some-path/Y");
Applications can be attached multiple times (at different paths) to both the internal-router as to several virtual hosts. A 'pure internal' application should only be attached to the internal router.
Caution
Note that internal/dynamic resources that require protocol specific attributes of the URI where it is invoked (like hostname) might yield errors or unexpected results when called via the riap internal protocol. Also beware that constructed URI's to secundary resources which are based on the 'own reference' can yield unexpected or at least different results when the resource is suddenly being called via the riap. Give these cases some special attention during your design, specially when porting stuff from other environments (e.g. servlet app)
Feature Availability
This feature landed in svn-trunk end of November 2007 (rev 2251). It will be part of the 1.1 release.
FIXME
50
When developing your Restlet code, you should always use the current context to get a logger. This will ensure the proper naming and filtering of your log records. Most classes like Restlet subclasses or Resource subclasses offer a "getLogger()" method. Otherwise, you can rely on the static "Context.getCurrentLogger()" method. Note also that the are two main types of log record in Restlet: The code related log records, for example used for tracing, debugging or error logging The access related log records, used to log the requests received by a component (identical to IIS or Apache logs)
It can often be difficult to configure your logging properties file because you don't always know precisely the logger names. For Restlet code, everything is under the root "org.restlet" logger so it is relatively easy.
51
However, as the Restlet extensions rely on many third-party library, you need to understand how each one handles logging in order to consistently configure you logging. Many of them rely on Apache Commons Logging API8 as a neutral API that can plug implementations such as Log4J9 or JDK Logging. Other use the neutral SLF4J, but in most of the cases, it is possible to redirect those alternative logging mechanisms to the JDK logging one. Here is an attempt to list the logger names used by those libraries. Please help us to complete this table. Library db4o Grizzly Bloat Java Activation Java Mail Java Servlet JAX-RS JAXB StAX JLine JXTA OAuth AntLR Commons Codec Package name com.db4o com.sun.grizzly edu.purdue.cs.bloat javax.activation javax.mail javax.servlet javax.ws.rs javax.xml.bind javax.xml.stream jline net.jxta net.oauth org.antlr.runtime org.apache.commons.c odec Logger name Comment
Commons FileUpload org.apache.commons.f ileupload Commons HTTP Client Commons IO Commons Lang Commons Logging Commons Pool MINA org.apache.commons.h org.apache.commons.h For more details, see ttpclient ttpclient.* the logging httpclient.wire.* documentation page10. org.apache.commons.i o org.apache.commons.l ang org.apache.commons.l ogging org.apache.commons.p ool org.apache.mina 52
org.apache.velocity org.bouncycastle freemarker org.jibx.runtime org.json junit org.mortbay.jetty org.mortbay.* Jetty chooses its logger from the property "org.mortbay.log.class ", biased towards SLF4J but overrideable
If the logger name you are looking for isn't listed, there is an easy way to detect it. You just have to call the static "com.noelios.restlet.util.TraceHandler.register()" method at the beginning of your program. It will replace the default console handler by a more compact one that will display the logger name for each log record received by the root logger (i.e. all the log records).
# This defines a whitespace separated list of class names for handler classes to load and register as handlers on # the root Logger (the Logger named ""). Each class name must be for a Handler class which has a default constructor. # Note that these Handlers may be created lazily, when they are first used. handlers=java.util.logging.FileHandler
In this first section, we declare one default handler that will receive the log records. It is a file handler that will be configured below.
# -----------------# Loggers properties # ------------------
53
In this second section, we indicate that by default we are only interested in log records with a WARNING level. We also configure the Mortbay's Jetty, Restlet API and NRE log levels to WARNING. This isn't necessary here but it can be useful when you need to lower the level of only one of them at some point, for debugging purpose for example. We also configured a logger for the WWW access log of our Restlet component. For information, our Component subclass has this code in its constructor:
getLogService().setLoggerName("com.noelios.web.WebComponent.www");
Also note that we use a specific handler for this logger, the AccessLogFileHandler which is provided in the NRE. It can be easily configurer to produce Apache-style HTTP log files.
# ------------------------# ConsoleHandler properties # ------------------------# Specifies the default level for the Handler (defaults to Level.INFO). # java.util.logging.ConsoleHandler.level=WARNING # Specifies the name of a Filter class to use (defaults to no Filter). # java.util.logging.ConsoleHandler.filter= # Specifies the name of a Formatter class to use (defaults to java.util.logging.SimpleFormatter). # java.util.logging.ConsoleHandler.formatter= # The name of the character set encoding to use (defaults to the default platform encoding). # java.util.logging.ConsoleHandler.encoding=
In the section above we have disabled the default ConsoleHandler configuration as we don't use it on our server-side application.
# -----------------------------# General FileHandler properties # -----------------------------# Specifies the default level for the Handler # java.util.logging.FileHandler.level=ALL (defaults to Level.ALL).
# Specifies the name of a Filter class to use (defaults to no Filter). # java.util.logging.FileHandler.filter= # Specifies the name of a Formatter class to use (defaults to java.util.logging.XMLFormatter) java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter # The name of the character set encoding to use (defaults to the default platform encoding). # java.util.logging.FileHandler.encoding= # Specifies an approximate maximum amount to write (in bytes) to any one file. # If this is zero, then there is no limit. (Defaults to no limit). java.util.logging.FileHandler.limit=10000000 # Specifies how many output files to cycle through (defaults to 1).
54
java.util.logging.FileHandler.count=100 # Specifies a pattern for generating the output file name. (Defaults to "%h/java%u.log"). # A pattern consists of a string that includes the following special components that will be replaced at runtime: # "/" the local pathname separator # "%t" the system temporary directory # "%h" the value of the "user.home" system property # "%g" the generation number to distinguish rotated logs # "%u" a unique number to resolve conflicts # "%%" translates to a single percent sign "%" java.util.logging.FileHandler.pattern=/home/prod/data/log/WebComponent-app-%u-%g.log # Specifies whether the FileHandler should append onto any existing files (defaults to false). # java.util.logging.FileHandler.append=
Here we specify the file size limit, the number of rotation files (100) and the file name template.
# ------------------------# LogFileHandler properties # ------------------------# Specifies the default level for the Handler (defaults to Level.ALL). # com.noelios.restlet.util.AccessLogFileHandler.level=ALL # Specifies the name of a Filter class to use (defaults to no Filter). # com.noelios.restlet.util.AccessLogFileHandler.filter= # Specifies the name of a Formatter class to use (defaults to java.util.logging.XMLFormatter) com.noelios.restlet.util.AccessLogFileHandler.formatter=com.noelios.restlet.util.AccessL ogFormatter # The name of the character set encoding to use (defaults to the default platform encoding). # com.noelios.restlet.util.AccessLogFileHandler.encoding= # Specifies an approximate maximum amount to write (in bytes) to any one file. # If this is zero, then there is no limit. (Defaults to no limit). com.noelios.restlet.util.AccessLogFileHandler.limit=10000000 # Specifies how many output files to cycle through (defaults to 1). com.noelios.restlet.util.AccessLogFileHandler.count=50 # Specifies a pattern for generating the output file name. (Defaults to "%h/java%u.log"). # A pattern consists of a string that includes the following special components that will be replaced at runtime: # "/" the local pathname separator # "%t" the system temporary directory # "%h" the value of the "user.home" system property # "%g" the generation number to distinguish rotated logs # "%u" a unique number to resolve conflicts # "%%" translates to a single percent sign "%" com.noelios.restlet.util.AccessLogFileHandler.pattern=/home/prod/data/log/WebComponent-w ww-%u-%g.log # Specifies whether the FileHandler should append onto any existing files (defaults to false). # com.noelios.restlet.util.AccessLogFileHandler.append=
This is similar to the previous section, but specific to our NRE AccessLogFileHandler log handler. This let's us use a specific log formatter called AccessLogFormatter, also provided by the NRE.
55
Notes
1. 2. 3. 4. 5. 6. 7. 8. 9. http://www.restlet.org/documentation/1.1/api/org/restlet/data/LocalReference.html http://www.restlet.org/documentation/1.1/nre/com/noelios/restlet/local/LocalClientHelper.html http://www.restlet.org/documentation/1.1/nre/com/noelios/restlet/local/ClapClientHelper.html http://restlet.tigris.org/issues/show_bug.cgi?id=374 http://restlet.tigris.org/issues/show_bug.cgi?id=157 http://java.sun.com/j2se/1.5.0/docs/guide/logging/index.html http://java.sun.com/j2se/1.5.0/docs/api/java/util/logging/LogManager.html http://commons.apache.org/logging/ http://logging.apache.org/log4j/
56
6 Restlet Extensions
6.1 Introduction
The Restlet framework is composed of three parts: The Restlet API The Noelios Restlet Engine (NRE) implementing the API Optional Restlet extensions.
This chapter presents all the extensions available in the Restlet framework and describes how to add those extensions to your application.
6.2 Description
The NRE lets you build complete Web applications by itself and is cpable of leveraging other open source projects to facilitate tasks such as generation of dynamic representations, management of uploaded files, sending of mails, etc. There are two types of extensions. The first one is for extensions built only on top of the Restlet API and typically provide new type of representations (JAXB, FreeMarker, JiBx, etc.) or support of important standards (Atom, WADL). The second one covers extensions to the Restlet engine such as client connectors, server connectors and authentication helpers.
6.3 Distribution
All extensions and their dependencies are shipped with the Restlet distribution by the way of JAR files. Adding an extension to your application is as simple as adding the archives of the chosen extension and its dependencies to the classpath. You can also have a look to the FAQ #41 and FAQ #52 which completes this subject.
57
6.4.2 Description
The Restlet extension for Atom provides a complete Atom API for both Web feeds and publication documents. This API is capable of both parsing and formatting Atom and APP XML documents compliants with the 1.0 specifications.
6.5.2 Description
This extension lets you receive files sent by POST or PUT requests and to parse the posted entity (which is actually an instance of the "Representation" class) and to extract a list of FileItems from it, each item corresponding to one file uploaded in the posted request, typically from a Web form. Please, refer to the FileUpload extension Javadocs6 and the FAQ #187 for more details. Here is the list of dependencies for this extension: Java Servlet 2.48 Apache Commons FileUpload 1.29
58
a component called "TestFileUpload" which creates a local HTTP server on port 80 and contains only one application (one instance of "MyApplication") attached to the path "/testFileUpload".
Thus, each request to the following uri "http://localhost/testFileUpload" will be handled by a new instance of "MyResource". The single representation of this resource is a web form with a file select control and a submit button. It allows to set up a request with an uploaded file that will be posted to the resource. Every Resource instance handles the POST request in method "acceptRepresentation" which accepts the posted entity as single parameter. The aim of the MyResource instance is to parse the request, get the file, save it on disk and send back its content as plain text to the client. Here is the content of the MyResource#acceptRepresentation method:
/** * Accepts and processes a representation posted to the resource. As * response, the content of the uploaded file is sent back the client. */ @Override public void acceptRepresentation(Representation entity) { if (entity != null) { if (MediaType.MULTIPART_FORM_DATA.equals(entity.getMediaType(), true)) { // // // // // // The Apache FileUpload project parses HTTP requests which conform to RFC 1867, "Form-based File Upload in HTML". That is, if an HTTP request is submitted using the POST method, and with a content type of "multipart/form-data", then FileUpload can parse that request, and get all uploaded files as FileItem.
// 1/ Create a factory for disk-based file items DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(1000240); // 2/ Create a new file upload handler based on the Restlet // FileUpload extension that will parse Restlet requests and // generates FileItems. RestletFileUpload upload = new RestletFileUpload(factory); List items; try { // 3/ Request is parsed by the handler which generates a // list of FileItems items = upload.parseRequest(getRequest()); // Process only the uploaded item called "fileToUpload" and // save it on disk boolean found = false; for (final Iterator it = items.iterator(); it .hasNext() && !found;) { FileItem fi = it.next(); if (fi.getFieldName().equals("fileToUpload")) { found = true; File file = new File("c:\\temp\\file.txt"); fi.write(file); } } // Once handled, the content of the uploaded file is sent // back to the client. Representation rep = null; if (found) { // Create a new representation based on disk file. // The content is arbitrarily sent as plain text.
59
rep = new FileRepresentation(new File( "c:\\temp\\file.txt"), MediaType.TEXT_PLAIN, 0); } else { // Some problem occurs, sent back a simple line of text. rep = new StringRepresentation("no file uploaded", MediaType.TEXT_PLAIN); } // Set the representation of the resource once the POST // request has been handled. getResponse().setEntity(rep); // Set the status of the response. getResponse().setStatus(Status.SUCCESS_OK); } catch (Exception e) { // The message of all thrown exception is sent back to // client as simple plain text getResponse().setEntity( new StringRepresentation(e.getMessage(), MediaType.TEXT_PLAIN)); getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST); e.printStackTrace(); } } } else { // POST request with no entity. getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST); } }
Before running this example, please add the following jars to the classpath: org.restlet (Restlet API) com.noelios.restlet (Noelios reference implementation) org.restlet.ext.fileupload (Restlet extension based on the Apache FileUpload project) org.apache.commons.fileupload (Apache FileUpload project) org.apache.commons.io (Apache FileUpload project)
6.6.2 Description
When you need to generate a dynamic document based on a data model and a FreeMarker template (skeleton document similar to a JSP page or an XSLT stylesheet), you just need to create an instance of the TemplateRepresentation class with the matching parameters and to set it as the response entity. Please, refer to the FreeMarker extension Javadocs11 and the FAQ #1012 for more details. Here is the list of dependencies for this extension: FreeMarker 2.313
60
6.7.2 Description
This connector supports the following protocol: HTTP, HTTPS. The list of supported specific parameters is available in the javadocs: HTTPS specific parameters15
6.8.2 Description
As pointed out by the Apache HTTPClient tutorial it is crucial to read entirely each response. It allows to release the underlying connection. Not doing so may cause future requests to block. See Apache HTTPClient 3.x tutorial18. This connector supports the following protocols: HTTP, HTTPS. The list of supported specific parameters is available in the javadocs: HTTP client parameters19
Here is the list of dependencies of this connector: Apache Commons HTTP Client 3.120 Apache Commons Codec 1.321 Apache Commons Logging 1.122
61
6.9.2 Description
This connector supports the following protocols: SMTP, SMTPS. The list of supported specific parameters is available in the javadocs: JavaMail client javadocs24
The mail and its properties (sender, recipient, subject, content, etc) have to be specified as an XML representation. Please refer to the JavaMail client javadocs25 for more details. Here is the list of dependencies of this connector: JavaMail API 1.426 JavaBeans Activation Framework 1.127
6.10.2 Description
The extension is composed of just one class, the JaxbRepresentation that extends the XmlRepresentation and is able to both serialize and deserialize a Java objects graph to/from an XML document.
62
6.11.2 Description
To run this example, you need the Restlet libraries. Download a 1.1 milestone from www.restlet.org/downloads/29. (For a general Restlet example take a look at http://www.restlet.org/documentation/1.1/firstSteps.) Now create a new Java Project, and add the following jars (resp. projects) to the classpath (right click on project, Properties, Java Build Path, Libraries (resp.Projects), Add): org.restlet (the core Restlet API) org.restlet.ext.jaxrs_1.0 (the JAX-RS Runtime) javax.ws.rs_1.0 (the JAX-RS API and also the specification) com.noelios.restlet (the Noelios Restlet Engine)
Depending of your needs you have to add the following: if you want to use the provider for javax.xml.transform.DataSource: add javax.activation_1.1 and javax.mail_1.4 if you want to use the provider for JAXB: add javax.xml.bind_2.1 and javax.xml.stream if you want to use the provider for JSON: add org.json_2.0
Click "Ok" twice. Now you are ready to start. - First we will create an example root resource class and then show how to get it running by the Restlet JAX-RS extension.
63
6.11.3.2 Create ApplicationConfig To provide a collection of root resource classes (and others) for a JAX-RS runtime you integrate these classes to an ApplicationConfig. Create a new class ExampleAppConfig in the same package with the following content:
package test.restlet.jaxrs; import java.util.HashSet; import java.util.Set; import javax.ws.rs.core.ApplicationConfig; public class ExampleApplication extends Application { public Set<Class<?>> getClasses() { Set<Class<?>> rrcs = new HashSet<Class<?>>(); rrcs.add(EasyRootResource.class); return rrcs; } }
The root resource class and the ApplicationConfig is specified by the JAX-RS specification. It can be used in any JAX-RS runtime environment. Now create a runtime environment instance and pass the ApplicationConfig instance to it. This is runtime environment specfic. Below you see this for the Restlet JAX-RS environment:
public class ExampleServer { public static void main(String[] args) throws Exception { // create Component (as ever for Restlet) Component comp = new Component(); Server server = comp.getServers().add(Protocol.HTTP, 8182); // create JAX-RS runtime environment JaxRsApplication application = new JaxRsApplication(comp.getContext()); // attach ApplicationConfig application.add(new ExampleAppConfig()); // Attach the application to the component and start it comp.getDefaultHost().attach(application); comp.start(); System.out.println("Server started on port " + server.getPort()); System.out.println("Press key to stop server"); System.in.read(); System.out.println("Stopping server"); comp.stop(); System.out.println("Server stopped"); } }
64
Start this class, open a browser and request http://localhost:8182/easy. Now you see the HTML representation. If you request the same URI with accepted media type "text/plain", you get a plain text representation. This example (a little bit extended) is available in the project org.restlet.example. See package org.restlet.test.jaxrs. There is another root resource class with a reacheable resource class and also an example with user authentication. A lot of more resource classes are available in the test project (org.restlet.test, packages starting with org.restlet.test.jaxrs). They are implemented for testing, and most of them do not do intelligent things ... :-) But they show the actual status of development of this JAX-RS runtime environment. This runtime environment is still under development, and I'm very busy continuing it ... 6.11.4.1 Run in a Servlet Container If you want to run the JAX-RS Application in a Servlet Container, create a subclass of the JaxRsApplication. In the constructor you could attach the ApplicationConfigs and sets the Guard and the RoleChecker (if needed).
public class MyJaxRsApplication extends JaxRsApplication { public MyJaxRsApplication(Context context) { super(context); this.add(new MyAppConfig()); this.setGuard(...); // if needed this.setRoleChecker(...); // if needed } }
For details to run this Application in a Servet Container take a look at Restlet FAQ30. You could use this subclass also in the example above:
// create JAX-RS runtime environment Application application = new MyJaxRsApplication(comp.getContext()); // if you use this kind, you don't need to attach the ApplicationConfig again.
Comments are welcome to the Restlet mailing list31 or directly to Stephan.Koops<AT>web.de ! This extension is the result of a (german) master thesis32.
6.12.2 Description
This connector supports the following protocol: JDBC. Restlet User Guide - Version 1.1 65
The SQL request and other kinds of parameters (such as pooling) are passed to the client connector via an XML representation. Please refer to the JDBC client javadocs34 for more details. The Response provides the result of the SQL request as a RowSetRepresentation which is a kind of XML representation of the ResultSet instance wrapped either in a JdbcResult or in a WebRowSet instance. See the RowSetRepresentation35 for more details. Here is the list of dependencies of this connector: Apache Commons DBCP 1.236 Apache Commons Pool 1.337 Apache Commons Logging 1.138
6.13.2 Description
This connector supports the following protocols: HTTP, HTTPS, AJP. The list of supported specific parameters is available in the javadocs: Jetty common parameters40 HTTP specific parameters41 HTTPS specific parameters42
Here is the list of dependencies of this connector: Jetty 6.143 Java Servlet 2.544
66
6.13.4.2 Description
6.13.4.2.1 Embedding Jetty
6.13.4.2.1.1 JettyAJPApplication.Class
package com.bjinfotech.restlet.practice.demo.microblog; import import import import import import import import import import org.restlet.Application; org.restlet.Component; org.restlet.Directory; org.restlet.Restlet; org.restlet.Router; org.restlet.Server; org.restlet.data.Protocol; com.noelios.restlet.ext.jetty.AjpServerHelper; com.noelios.restlet.ext.jetty.HttpServerHelper; com.noelios.restlet.ext.jetty.JettyServerHelper;
public class JettyAJPApplication extends Application { public static void main(String[] argv) throws Exception{ Component component=new Component(); Application application=new Application(component.getContext()){ @Override public Restlet createRoot(){ final String DIR_ROOT_URI="file:///E:/eclipse3.1RC3/workspace/RestletPractice/static_files/"; Router router=new Router(getContext()); Directory dir=new Directory(getContext(),DIR_ROOT_URI); dir.setListingAllowed(true); dir.setDeeplyAccessible(true); dir.setNegotiateContent(true); router.attach("/www/",dir); return router; } }; ... //create embedding jetty server Server embedingJettyServer=new Server( component.getContext(), Protocol.HTTP, 8182, component ); //construct and start JettyServerHelper JettyServerHelper jettyServerHelper=new HttpServerHelper(embedingJettyServer); jettyServerHelper.start();
67
//create embedding AJP Server Server embedingJettyAJPServer=new Server( component.getContext(), Protocol.HTTP, 8183, component ); //construct and start AjpServerHelper AjpServerHelper ajpServerHelper=new AjpServerHelper(embedingJettyAJPServer); ajpServerHelper.start(); } }
2008-02-13 15:33:54.890::INFO: 2008-02-13 15:33:54.953::INFO: 2008-02-13 15:33:55.140::INFO: 2008-02-13 15:33:55.140::INFO: 2008-02-13 15:33:55.140::INFO: 2008-02-13 15:33:55.140::INFO:
Logging to STDERR via org.mortbay.log.StdErrLog jetty-6.1.x Started SelectChannelConnector @ 0.0.0.0:8182 jetty-6.1.x AJP13 is not a secure protocol. Please protect port 8183 Started Ajp13SocketConnector @ 0.0.0.0:8183
put mod_jk.so into your <apache-root>/modules/ directory you can download mod_jk.so here http://archive.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/ add the entry below in your httpd.conf apache configuration file located in <apache-root> /conf/ directory:
<IfModule !mod_jk.c> LoadModule jk_module </IfModule> <IfModule mod_jk.c> JkWorkersFile "conf/worker.properties" JkLogFile "logs/mod_jk.log" JkLogLevel info JkLogStampFormat "[%a %b %d %H:%M:%S %Y] " JkOptions +ForwardKeySize +ForwardURICompat </IfModule> modules/mod_jk.so
LoadModule jk_module modules/mod_jk.so tells your apache server to load the mod_jk libray and where it is located. JkWorkersFile conf/worker.properties tells mod_jk where your worker.properties is located. JkLogFile logs/mod_jk.log tells mod_jk where to write mod_jk related Logs.
68
After adding the mod_jk configuration you may add a VirtualHost Entry in the same file (httpd.conf) as long as its located below your mod_jk configuration entry:
<VirtualHost host:*>
ServerName yourserver
ServerAdmin user@yourserver
## you may add further entries concerning log-files, log-level, URL-rewriting, ...
JkMount /* jetty
</VirtualHost>
Add a worker file worker.properties in your <apache-root>/conf/ add the entries below, and make sure to specify your ip-address or hostname in worker.jetty.host property entry to where your jetty application is runnning
worker.list=jetty worker.jetty.port=8009 worker.jetty.host=<server name or ip where your jetty will be running> worker.jetty.type=ajp13
mod_jk
Linux(ubuntu)
mod_jk-1.2.14 mod_jk-1.2.15 mod_jk-1.2.18 mod_jk-1.2.19 Apache 2.0 (2.0.59) mod_jk-1.2.14 mod_jk-1.2.15 mod_jk-1.2.18 mod_jk-1.2.19 Apache 2.2 mod_jk-1.2.14 Restlet User Guide - Version 1.1 No Binary Available
Not yet tested Not yet tested Not yet tested Not yet tested
69
No Binary Available
[To be detailled]
6.13.4.2.5 More Resource
Jetty doc:Configuring+AJP13+Using+mod_jk50 Apache Httpd Document51 HttpServerHelper Class API52 Server Class API53 AjpServerHelper Class API54
6.14.2 Description
The extension is composed of just one class, the JibxRepresentation that extends the XmlRepresentation and is able to both serialize and deserialize a Java objects graph to/from an XML document.
6.15.2 Description
This extension adds support for JSON representations. It enables you to create JsonRepresentation instances from the two kinds of structure defined by JSON: objects and arrays, and to make the reverse conversion. JsonRepresentations can also be generated from String and any kind of Representation. Please, refer to the JSON extension Javadocs57 and the FAQ #1058 for more details and have a look to the Restlet wiki59 for some sample code. Here is the list of dependencies for this extension: Restlet User Guide - Version 1.1 70
JSON 2.060
6.16.2 Description
This connector supports the following protocols: HTTP, HTTPS. The list of supported specific parameters is available in the javadocs: HTTP client parameters62
6.17.2 Description
Currently the extension is considered experimental and is under-documented. If anyone interested could help document this feature that would be very appreciated.
6.17.3 References
Some links to start with: "OAuth Core 1.0" http://oauth.net/core/1.0/ "Getting Started - Part I" http://oauth.net/documentation/getting-started "Explaining OAuth" http://www.hueniverse.com/hueniverse/2007/09/explaining-oaut.html Beginners Guide to OAuth Part I : Overwiew63 Part II : Protocol Workflow64 Part III : Security Architecture65 Part IV : Signing Requests66
71
6.18.2 Description
It enables you to run a Restlet based application inside any Servlet container such as Tomcat. Please, refer to the ServerServlet extension Javadocs67 and the FAQ #268 for more details. Here is the list of dependencies for this extension: Java Servlet 2.469
6.19.2 Description
This connector supports the following protocols: HTTP, HTTPS. The list of supported specific parameters is available in the javadocs: Simple common parameters71 HTTP specific parameters72 HTTPS specific parameters73
5. 6.
6.20.2 Introduction
This extension provides various modes of integration between the Restlet framework and the popular Spring framework. Historically, this extension emerged from the needs of Spring users, stuck between the Spring's mechanism of Dependency Injection mostly based on JavaBean setters (Setter Injection) and constructor arguments (Constructor Injection), and the conceptual choices of the Restlet framework that didn't systematize the use of simple POJOs.
6.20.3 Description
This extension aims at providing a better and more natural integration. It comes in two part, one extension for the Restlet API (org.restlet.ext.spring) and another for the Restlet engine (com.noelios.restlet.ext.spring). Please, refer to the Spring extension Javadocs75 and the FAQ #23 76 for more details and have a look the Restlet wiki77 for several sample codes. Here is the list of dependencies for this extension: Spring framework 2.078
Routers, Finders and Resources from your existing Servlet-based Spring code. You can check the Javadocs for details. Finally, there is also a SpringFinder class available in the Spring extension. It hasn't any specific dependency to Spring, but the addition of a parameter-less createResource() method allows the usage of the Spring's "lookup-method" mechanism. In Restlet 1.1, the Spring extensions received several contributions, increasing the number of ways to integrate Restlet with Spring. There is now a RestletFrameworkServlet, a SpringServerServlet, SpringBeanFinder and SpringBeanRouter. Please check the Javadocs of the org.restlet.ext.spring and com.noelios.restlet.ext.spring modules for more details.
The second mechanism is based on the Spring utilities schema and is actually more compact:
<!-- Restlet Component bean --> <bean id="component" class="org.restlet.ext.spring.SpringComponent"> ... </bean> <!-- Application bean --> <bean id="application" class="org.restlet.Application"> <constructor-arg> <util:property-path path="component.context" /> </constructor-arg> ... </bean>
You also have to make sure that the util namespace is properly declared in your XML configuration header. Here is a snippet for Spring 2.5:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
74
xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"> <!-- Add you <bean/> definitions here --> </beans>
This utilities mechanism is quite powerful and flexible, for more information check this page80.
As a result, the main method has become very simple. It loads a Spring context based on two configuration metadata files, one for the preceding top-level beans, and one for the application-specific beans shown below. It then starts up the top-level Restlet Component.
public static void main(String... args) throws Exception { // load the Spring application context ApplicationContext springContext = new ClassPathXmlApplicationContext(
75
new String[] { "applicationContext-router.xml", "applicationContext-server.xml" }); // obtain the Restlet component from the Spring context and start it ((Component) springContext.getBean("top")).start(); }
Next, we look at the configuration of the application-specific Router. We use a SpringRouter for this purpose, which is configured using a map of URI patterns to resources. The SpringFinder beans provide the extra level of indirection required to create Resource instances lazily on a per-request basis. In this example, the last URI pattern has to be customized to accept complete URIs (possibly including slashes) as the last component of the pattern. We use Spring's nested properties to drill into the configuration of the URI pattern along with Spring's mechanism for accessing a static field in a class.
<bean id="root" class="org.restlet.ext.spring.SpringRouter"> <property name="attachments"> <map> <entry key="/users/{username}"> <bean class="org.restlet.ext.spring.SpringFinder"> <lookup-method name="createResource" bean="userResource" /> </bean> </entry> <entry key="/users/{username}/bookmarks"> <bean class="org.restlet.ext.spring.SpringFinder"> <lookup-method name="createResource" bean="bookmarksResource" /> </bean> </entry> <entry key="/users/{username}/bookmarks/{URI}"> <bean class="org.restlet.ext.spring.SpringFinder"> <lookup-method name="createResource" bean="bookmarkResource" /> </bean> </entry> </map> </property> <property name="routes[2].template.variables[URI]"> <bean class="org.restlet.util.Variable"> <constructor-arg ref="org.restlet.util.Variable.TYPE_URI_ALL" /> </bean> </property> </bean> <bean id="org.restlet.util.Variable.TYPE_URI_ALL" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" />
Unlike the preceding singleton beans, we define the Resources as prototype beans so that they get instantiated separately for each request. All of the Resource beans depend on the db4o85 ObjectContainer and are configured analogously, so we show only UserResource here.
<bean id="userResource" class="org.restlet.example.book.rest.ch7.spring.UserResource" scope="prototype"> <property name="container" ref="db4oContainer" /> </bean>
76
<bean id="db4oConfiguration" class="org.springmodules.db4o.ConfigurationFactoryBean"> <property name="updateDepth" value="2" /> <property name="configurationCreationMode" value="NEW" /> </bean>
As mentioned above, we added the following elements to each application-specific Resource: An empty default constructor. An init method containing the code originally in the non-default constructor. That constructor now simply invokes the init method, although it is no longer used in this context. An instance variable and getter/setter pair for the db4o ObjectContainer.
Currently, the init method resets these properties to their default values but, in the Spring component life cycle, is invoked after Spring sets the properties. An obvious workaround is to refine the init method like so:
@Override public void init(Context context, Request request, Response response) { final ResourcePropertyHolder backup = new ResourcePropertyHolder(); BeanUtils.copyProperties(this, backup); super.init(context, request, response); BeanUtils.copyProperties(backup, this); }
6.20.7.2 Configuration of representation templates In addition, it would be quite useful if one could map media types to representation templates in Spring. In the following example, we explore this idea further by mapping different media types to different Freemarker and JSON representation factories. Whenever a Resource creates a concrete representation, it passes a uniform data model to the representation factory, which then instantiates the template with the data model and returns the resulting representation. (The Freemarker configuration is also handled by Spring.)
<bean id="resource" class="helloworldrestlet.HelloWorldResource" scope="prototype"> <property name="available" value="true" /> <property name="representationTemplates"> <map> <entry key-ref="org.restlet.data.MediaType.TEXT_PLAIN" value-ref="hwFreemarkerTextPlain" /> <entry key-ref="org.restlet.data.MediaType.TEXT_HTML" value-ref="hwFreemarkerTextHtml" /> <entry key-ref="org.restlet.data.MediaType.APPLICATION_JSON" value-ref="jsonRepresentationFactory" /> </map> </property> </bean> <bean id="hwFreemarkerTextPlain" class="edu.luc.etl.restlet.spring.FreemarkerRepresentationFactory"> <property name="templateName" value="hw-plain.ftl" /> <property name="freemarkerConfig" ref="freemarkerConfig" /> </bean> <bean id="hwFreemarkerTextHtml" class="edu.luc.etl.restlet.spring.FreemarkerRepresentationFactory"> <property name="templateName" value="hw-html.ftl" /> <property name="freemarkerConfig" ref="freemarkerConfig" /> </bean> <bean id="jsonRepresentationFactory" class="edu.luc.etl.restlet.spring.JsonRepresentationFactory" /> <!-- omitted beans for specific MediaType static fields --> <bean id="freemarkerConfig" class="freemarker.template.Configuration"> <property name="directoryForTemplateLoading" value="src/test/resources/presentation" /> <property name="objectWrapper"> <bean class="freemarker.template.DefaultObjectWrapper" /> </property> </bean>
When using this approach, the Resources themselves become very simple, for example:
78
public class HelloWorldResource extends ConfigurableRestletResource { @Override public Representation represent(Variant variant) { final Map<String, Object> dataModel = Collections.singletonMap("DATE", (Object) new Date()); return createTemplateRepresentation(variant.getMediaType(), dataModel); } }
A working proof-of-concept for this approach is available through CVS from :pserver:anonymous@cvs.cs.luc.edu:/root/laufer/433, module ConfigurableRestletResource. Support for the missing configuration of representations tied to responses to non-GET requests is in the works.
6.21.2 Description
6.21.2.1 JsslutilsSslContextFactory The JsslutilsSslContextFactory class is a wrapper for jsslutils.sslcontext.SSLContextFactory. It has to be constructed with the instance to wrap and is therefore only suitable to be used in the context sslContextFactory attribute, not parameter. This is more likely to be used for more specialised features such as the key or trust manager wrappers of jSSLutils. 6.21.2.2 PkixSslContextFactory The PkixSslContextFactory class is a class that uses jsslutils.sslcontext.PKIXSSLContextFactory. It provides a way to configure the key store, the trust store (required for client-side authentication) and the server alias. As part of its trust manager configuration, it provides a way to set up certificate revocation lists (CRLs).
6.21.2.2.1 Example using the Component XML configuration:
<component xmlns="http://www.restlet.org/schemas/1.1/Component" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.restlet.org/schemas/1.1/Component"> <client protocol="FILE" /> <server protocol="HTTPS" port="8183"> <parameter name="sslContextFactory" value="com.noelios.restlet.ext.ssl.PkixSslContextFactory" /> <parameter name="keystorePath" value="/path/to/keystore.p12" /> <parameter name="keystoreType" value="PKCS12" /> <parameter name="keystorePassword" value="testtest" /> <parameter name="keyPassword" value="testtest" /> <parameter name="truststorePath" value="/path/to/truststore.jks" /> <parameter name="truststoreType" value="JKS" /> <parameter name="truststorePassword" value="testtest" /> <parameter name="crlUrl" value="file:///path/to/crl.crl" />
79
<parameter name="wantClientAuthentication" value="true" /> </server> <defaultHost> <attach uriPattern="" targetClass="org.restlet.example.tutorial.Part12" /> </defaultHost> </component>
There can be multiple crlUrl parameters. In addition, two other parameters can be set:
sslServerAlias,
which will use a particular alias from the key store. disableCrl, which should be set to "true" if CRLs are not to be used.
The wantClientAuthentication parameter is handled by this the SslContextFactory, but is often used in conjunction with it.
6.21.2.2.2 Example embedded within the program, using two connectors:
Component component = new Component(); Server server1 = component.getServers().add(Protocol.HTTPS, "host1.example.org", 8083); Series<Parameter> param1 = server1.getContext().getParameters(); param1.add("sslContextFactory","com.noelios.restlet.ext.ssl.PkixSslContextFactory"); param1.add("keystorePath","/path/to/keystore1.p12"); param1.add("keystorePassword","..."); param1.add("keystoreType","PKCS12"); //... Server server2 = component.getServers().add(Protocol.HTTPS, "host2.example.com", 8083); Series<Parameter> param2 = server2.getContext().getParameters(); param2.add("sslContextFactory","com.noelios.restlet.ext.ssl.PkixSslContextFactory"); param2.add("keystorePath","/path/to/keystore2.p12"); //...
This example uses two certificates depending on which server connector (and thus which listening socket) is used.
6.22.2 Description
This extension lets you generate Representations based on the Velocity template engine91. Please, refer to the Velocity extension Javadocs92 and the FAQ #1093 for more details. Here is the list of dependencies for this extension: Apache Velocity 1.594 80
For example:
<grammars> <include href="NewsSearchResponse.xsd"/> <include href="Error.xsd"/> </grammars>
NB: at this time, the WADL extension of the Restlet framework supports only "included" and not "inline" schemas via the GrammarsInfo#includes attribute. Then, for XML-based representations, the "element" attribute specifies the qualified name of the root element as described within the grammars section. For example:
<representation mediaType="application/xml" element="yn:ResultSet"/>
81
Then, at the level of the subclass of WadlResource, update the RepresentationInfo#element attribute:
RepresentationInfo formRepresentation = new RepresentationInfo(); formRepresentation.setXmlElement("yn:ResultSet");
82
6.24.3.2 Architecture Following picture depicts Oracle XDB Restlet adapter and Oracle components. To be added soon. Return to main document (page 82).
JDK 1.5 (included at your ORACLE_HOME/jdk directory) Ant 1.7.0+104 an 11g target database, tested with 11.1.0.6.0+ By now Oracle Restlet Adapter is only available through SVN access or using nightly builds, checkout SVN source105 or download an snapshop version106.
6.24.4.1.2 Installing
First edit into your home directory a file named build.properties with: # Restlet project # xdb_11.1 specific sqlnet.string=test jdbc.username=RESTLET jdbc.password=RESTLET jdbc.sysusr=sys jdbc.syspwd=change_on_install sqlnet.string property is a valid Oracle SQLNet connect string to the target database. jdbc.{username|password} are a valid Oracle user name and password to be created for storing Restlet code. Note that in Oracle 11g user name and password are case sensitive by default, so use always uppercase values to work well with the .sql script provided in this installer. jdbc.{sysusr|syspwd} are a valid Oracle DBA User account used to create above user schema and other related task only performormed by user who have DBA role.
Also is necessary a valid ORACLE_HOME environment variable defined to a valid Oracle 11g home directory, this variable then is used to locate for example the SQLPlus application. Finally go the directory: # cd src/com.noelios.restlet.ext.xdb_11.1/resources and execute Ant without argument: # ant To start using XDB Adapter ant without arguments is the only target required in a fresh database install. Other targets are provided during development stage, for example if you update the adapter code only the target load-server-side-runtime is required to re-install it. Restlet User Guide - Version 1.1 83
Oracle databases do not enable by default XMLDB HTTP repository access. To enable it using SQLPlus connected as SYSDBA execute: SQL> exec dbms_xdb.sethttpport(8080); Restart your database and test with a browser or any WebDAV enable file manager a connection to http://localhost:8080/ Return to main document (page 82).
Test your REST examples with your favorite browser using these URLs (they where configured as XMLDB Servlets by src/com.noelios.restlet.ext.xdb_11.1/resources/sql/postInstall.sql script): http://localhost:8080/searchapp/search?kwd=marcelo+ochoa http://localhost:8080/userapp/users/scott/orders/300 Note: XMLDB is an HTTP 1.0 complaint connector, usually modern browsers try to connect using HTTP 1.1 so you can experiment that the browser leave the connection open because is trying to use Keep-alive feature.
6.24.5.1.2 Tests using telnet
Some test can be done by using telnet application to see which headers are sent and got as response from REST WS. For example: [mochoa@mochoa resources]$ telnet localhost 8080 Trying 127.0.0.1... Connected to live.dbprism.mochoa.dyndns.org (127.0.0.1). Escape character is '^]'. GET /userapp/users/scott/orders/300 HTTP/1.0 HTTP/1.1 200 OK MS-Author-Via: DAV DAV: 1,2,<http://www.oracle.com/xdb/webdav/props> Date: Tue, 03 Jun 2008 19:18:11 GMT Server: Noelios-Restlet-Engine/1.1.snapshot Content-Type: text/plain; charset=ISO-8859-1 Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept Content-Length: 28 Order "300" for user "scott" 6.24.5.2 Minimalistic test comparing REST versus native SOAP
6.24.5.2.1 Benchmarking REST application
As you can see in a previous section there is simple User application which returns orders for scott user. Restlet User Guide - Version 1.1 84
Using ApacheBench you can test the application executing: ab -n {total_request} -c {concurrent_request} http://localhost:8080/userapp/users/scott/orders/300 Where total_request is number of request sent by Apache benchmark paralleling it in concurrent_request request. A result of this execution on my notebook can be compared in this Google sheet107.
6.24.5.2.2 Testing a similar WS implemented using SOAP
A similar functionality can be implemented using XMLDB Native SOAP WS108 . For doing that create this Java source at Scott's schema: create or replace and compile java source named "my.OrderCalculator" as package my; import java.util.logging.Level; import java.util.logging.Logger; public class OrderCalculator { /** * Java Util Logging variables and default values */ private static Logger logger = null; /** * Constant used to get Logger name */ static final String CLASS_NAME = OrderCalculator.class.getName(); static { logger = Logger.getLogger(CLASS_NAME); logger.setLevel(Level.ALL); } public static String getOrder(String userName, int orderId) { logger.entering(CLASS_NAME,"getOrder",new Object [] {userName,new Integer(orderId)}); logger.exiting(CLASS_NAME,"getOrder","Order '"+orderId+"' for user '"+userName+"'"); return "Order '"+orderId+"' for user '"+userName+"'"; } } / Note that I have added JDK Logging functionality to compare a closer example to Restlet functionality, obviously routing and many other default Restlet functionalities are not compared with this example. And his PLSQL Call Spec: CREATE OR REPLACE PACKAGE orders_calculator AUTHID CURRENT_USER AS FUNCTION getOrder(user_name IN VARCHAR2, order_id IN NUMBER) RETURN VARCHAR2 as LANGUAGE JAVA NAME 'my.OrderCalculator.getOrder(java.lang.String, int) return java.lang.String'; END orders_calculator; / Restlet User Guide - Version 1.1 85
As you can see OrderCalculator class is using JDK logging package, to get JDK logging working this grant is required: SQL> exec dbms_java.grant_permission( 'SCOTT', 'SYS:java.util.logging.LoggingPermission', 'control', '' ); SQL> commit; Finally to send a POST message using Apache benchmark its necessary to edit a POST XML message like: <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://xmlns.oracle.com/orawsv/SCOTT/ORDERS_CALCULATOR/GETOR DER"> <env:Header/> Command: <ns1:SVARCHAR2-GETORDERInput> <ns1:USER_NAME-VARCHAR2-IN>scott</ns1:USER_NAME-VARCHAR2-IN> <ns1:ORDER_ID-NUMBER-IN>300</ns1:ORDER_ID-NUMBER-IN> </ns1:SVARCHAR2-GETORDERInput> </env:Body> </env:Envelope> The ApacheBench command line will look like: ab -A scott:tiger -H 'SOAPAction: "GETORDER"' -p /tmp/soap-post-func.txt -n {total_request} -c {concurrent_request} http://loca lhost:8080/orawsv/SCOTT/ORDERS_CALCULATOR/GETORDER Where: -A scott:tiger is the HTTP authorization information (XMLDB Native WS do not accept anonymous login) -H 'SOAPAction: "GETORDER" is a required HTTP header for SOAP -p /tmp/soap-post-func.txt is file which have the POST XML message showed above and the URL is a default URL used to execute Native SOAP WS in XMLDB
Do not forget grant XDB_WEBSERVICES and XDB_WEBSERVICES_OVER_HTTP roles to SCOTT, also register the orawsv Servlet.
6.24.5.2.3 Testing with Apache mod_mem_cache.
One of the most important consequence of REST architecture is that is on top on HTTP protocol, so why not include for example reverse proxy in front of Oracle XMLDB Restlet adapter. On Linux you can try this configuration: Add this to /etc/httpd/modules.d/57_mod_mem_cache.conf file: ..... <IfModule mod_cache.c> # CacheEnable - A cache type and partial URL prefix below which caching is enabled #CacheEnable mem /manual #CacheEnable fd /images CacheEnable mem /userapp CacheEnable mem /orawsv </IfModule> Restlet User Guide - Version 1.1 86
.... This will enable mod_mem_cache to any URL starting with /userapp/ directory, this directory will be retrieved using Apache mod_proxy. Edit /etc/httpd/modules.d/30_mod_proxy.conf adding these lines: <IfModule mod_proxy.c> .... SetEnv proxy-nokeepalive 1 .... ProxyPass /userapp/ http://localhost:8080/userapp/ ProxyPassReverse /userapp/ http://localhost:8080/userapp/ ProxyPass /orawsv/ http://localhost:8080/orawsv/ ProxyPassReverse /orawsv/ http://localhost:8080/orawsv/ .... </IfModule> This will redirect automatically any URL http://localhost:80/userapp/ to XMLDB http://localhost:8080/userapp/. Finally start Apache Web Server and test the URL http://localhost/userapp/users/scott/orders/300 note now we are using port 80, not port 8080. To boost your REST WS performance you can change, for example, the expiration header of the response, many WS can use this trick a typically example is a weather service which is updated every 30 minutes. In our User application this change can be injected at org.restlet.example.tutorial.OrderResource class method represent, for example: @Override public Representation represent(Variant variant) throws ResourceException { Representation result = null; if (variant.getMediaType().equals(MediaType.TEXT_PLAIN)) { result = new StringRepresentation("Order \"" + this.orderId + "\" for user \"" + this.userName + "\""); } Date expirationDate = new Date(System.currentTimeMillis()+10000); result.setExpirationDate(expirationDate); return result; } This small change represent for 100 request in User application a difference between: Requests per second: 49.65 [#/sec] (mean) to Requests per second: 1407.90 [#/sec] (mean) and 1 request to XMLDB instead of 100 request, reducing a lot a server workload. There is no change with our SOAP WS because POST messages are not cached by mod_mem_cache reverse proxy.
6.24.5.2.3.1 Testing performance with Apache JMeter
XMLDB Restlet Adapter can be tested with Apache JMeter, here some captures with the above REST and SOAP WS. Test plan used with Users Restlet example: Thread Group -> Thread Properties Number of Threads (users): 10 Ramp Up Period (in seconds): 0 Restlet User Guide - Version 1.1 87
Loop Count: 200 HTTP Request -> Web Server Server Name or IP: localhost HTTP Request -> HTTP Request Protocol: http Method: GET Path: /userapp/users/scott/orders/300 Gaussian Random Timer -> Thread Delay Properties Deviation (in milliseconds): 100.0 Constant Delay Offset (in milliseconds): 300
6.24.5.2.4 Graph Results
Test plan used with Users SOAP example: Number of Threads (users): 10 Ramp Up Period (in seconds): 0 Loop Count: 200 SOAP/XML-RPC Request -> Web Server Server Name or IP: localhost HTTP Request -> HTTP Request URL: http://localhost:8080/orawsv/SCOTT/ORDERS_CALCULATOR/GETORDER Send SOAPAction: GETORDER User KeepAlive: true SOAP/XML-RPC Data Filename: /tmp/soap-post-func.txt HTTP Header Manager -> Headers Stored in the Header Manager Restlet User Guide - Version 1.1 88
Authorization: Basic c2NvdHQ6dGlnZXI= (Base 64 encoding of scott/tiger) Gaussian Random Timer -> Thread Delay Properties Deviation (in milliseconds): 100.0 Constant Delay Offset (in milliseconds): 300 /tmp/soap-post-func.txt file content: <?xml version = '1.0'?> <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://xmlns.oracle.com/orawsv/SCOTT/ORDERS_CALCULATOR/GETOR DER"> <env:Header/> <env:Body> <ns1:SVARCHAR2-GETORDERInput> <ns1:USER_NAME-VARCHAR2-IN>scott</ns1:USER_NAME-VARCHAR2-IN> <ns1:ORDER_ID-NUMBER-IN>300</ns1:ORDER_ID-NUMBER-IN> </ns1:SVARCHAR2-GETORDERInput> </env:Body> </env:Envelope>
6.24.5.2.5 Graph Results
89
UsersRestlet: [Noelios Restlet Engine] - Schema: RESTLET class: RESTLET:org.restlet.example.tutorial.Part12 loader: class oracle.aurora.rdbms. DbmsJava UsersRestlet: [Noelios Restlet Engine] - Try to load 'org.restlet.attribute.server' parameter from '/home/'||USER||'/restlet/UsersRestlet.xml UsersRestlet: [Noelios Restlet Engine] - Attaching application: org.restlet.example.tutorial.Part12@8b9e5a01 to URI: /userapp Jun 4, 2008 6:28:27 PM com.noelios.restlet.http.HttpServerCall parseHost INFO: Couldn't find the mandatory "Host" HTTP header. Jun 4, 2008 6:28:27 PM com.noelios.restlet.ext.xdb.XdbServletWarClientHelper start INFO: efective user is: ANONYMOUS *** 2008-06-04 15:28:27.588 Jun 4, 2008 6:28:27 PM com.noelios.restlet.LogFilter afterHandle INFO: 2008-06-04 18:28:27 8080 GET /userapp/users/scott/orders/300 200 28 - 155 http://null 6.24.6.2 How many concurrent session are started by Oracle? As mentioned in previous answer the Oracle JVM session which receives the request is automatically started by Oracle, how many concurrent sessions are started by Oracle Listener is automatically computed by Oracle and you don't care about it. My testing shows that for heavy workload there is around 5 to 7 % of concurrent request. 6.24.6.3 Which is the effective Oracle user when run a REST WS? It depends on the HTTP authorization mechanism. REST WS which are available as anonymous access, no HTTP authorization information, runs with ANONYMOUS Oracle user and PUBLIC database role. REST WS which are authorized though HTTP header Authorization are executed with his effective Oracle user, for example SCOTT. 6.24.6.4 How to enable anonymous REST WS? First unlock ANONYMOUS Oracle account. By default XMLDB Restlet Adapter do this command at postInstall.sql script SQL> alter user anonymous account unlock; Then you have to register your Restlet application into XMLDB configuration file (named /xdbconfig.xml) with this Servlet role: <servlet xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd"> <servlet-name>UsersRestlet</servlet-name> <servlet-language>Java</servlet-language> <display-name>Restlet Servlet</display-name> <servlet-class>com.noelios.restlet.ext.xdb.XdbServerServlet</servlet-class> <servlet-schema>PUBLIC</servlet-schema> <init-param xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd"> <param-name>org.restlet.application</param-name> <param-value>RESTLET:org.restlet.example.tutorial.Part12</param-value> <description>REST User Application</description> </init-param> <security-role-ref xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd"> Restlet User Guide - Version 1.1 91
<description/> <role-name>PUBLIC</role-name> <role-link>PUBLIC</role-link> </security-role-ref> </servlet> Above registration can be done by a following PLSQL script executed logged as SYS: DECLARE configxml SYS.XMLType; begin dbms_xdb.deleteServletMapping('UsersRestlet'); dbms_xdb.deleteServlet('UsersRestlet'); dbms_xdb.addServlet(name=>'UsersRestlet', language=>'Java', class=>'com.noelios.restlet.ext.xdb.XdbServerServlet', dispname=>'Restlet Servlet',schema=>'PUBLIC'); -- Modify the configuration -- Due this servlet provide public access, it can not load -- '/home/'||USER||'/restlet/UsersRestlet.xml' from XMLDB repository SELECT INSERTCHILDXML(xdburitype('/xdbconfig.xml').getXML(),'/xdbconfig/sysconfig/protoc olconfig/httpconfig/webappconfig/servletconfig/servlet-list/servlet[servlet-name="UsersRe stlet"]','init-param', XMLType('<init-param xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd"> <param-name>org.restlet.application</param-name> <param-value>RESTLET:org.restlet.example.tutorial.Part12</param-value> <description>REST User Application</description> </init-param>'),'xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd"') INTO configxml FROM DUAL; -- Update the configuration to use the modified version --I got this error at this line : dbms_xdb.cfg_update(configxml); dbms_xdb.addServletSecRole(SERVNAME => 'UsersRestlet',ROLENAME => 'PUBLIC',ROLELINK => 'PUBLIC'); dbms_xdb.addServletMapping('/userapp/*','UsersRestlet'); commit; end; / commit; For more information on how to register a Servlet with anonymous access read Using Protocols to Access the Repository109. 6.24.6.5 How can I define my Application in XdbServerServlet? XMLDB do not accept context parameters so unlike com.noelios.restlet.ext.servlet.ServerServlet class, XdbServerServlet have two way to define org.restlet.application parameter. First option was used in previous examples, it means using Servlet 2.2 <init-param> tag, this is very useful for anonymous REST applications. For authenticated applications there is another option which is to put an XML file at XMLDB repository using this predefined path: /home/USER/restlet/appName.xml Restlet User Guide - Version 1.1 92
where USER is the efective connected username, for example SCOTT, and appName is the servlet name; name argument in dbms_xdb.addServlet procedure used for registering Servlet in XMLDB, in above example is UsersRestlet. This file look like: <restlet-app> <org.restlet.application>org.restlet.example.tutorial.Part12</org.restlet.application> </restlet-app> Second option do not require DBA role if you want to update your application class name. Return to main document (page 82).
93
6.24.8.3 Dependencies This project depends on: Restlet Artifacts, version 1.1-SNAPSHOT org.restlet com.noelios.restlet com.noelios.restlet.ext.xdb com.noelios.restlet.ext.servlet
Oracle JDBC 11g library, version 11.1.0 JUnit library, version 3.8.1 Servlet API, version 2.2
6.24.8.4 Where to download This project is downloaded from several sources as follow: - Project binary archive Zip115 or Tar.gz 116 - Project source from CVS repository, follow instructions from (http://sourceforge.net/cvs/?group_id=56183) module lucene-restlet. - Lucene Domain Index binary distribution117, download and extract in any directory, then follow Maven install instruction to add to your local repository. - RESTs artifacts, automatically download from http://maven.restlet.org/. - Lucene artifacts, automatically downloaded from Maven's public repository. 6.24.8.5 Directory structure This project follows Maven standard layout. Here a list of the content of each one: src/main/java (source of Lucene WS API implementation) src/main/scripts (HTTP test messages to show Lucene WS API usage) src/main/sql (post installation script to register Lucene WS API as XMLDB Servlet) Restlet User Guide - Version 1.1 94
src/main/webapp (a Web Application layout to test and debug this implementation outside the OJVM using Jetty) src/test/java (Client side JUnit tests suites which consumes Lucene REST WS API, coming soon) src/test/jmeter (Apache JMeter test suites for testing WS performance) src/resources (a build.properties file used to deploy Lucene WS API inside the OJVM) 6.24.8.6 Configuration Parameters Several parameters at the boton of pom.xml file, properties section, are used during install target, here a brief explanation of each one: .... <properties> <sqlplus.app.value>${env.ORACLE_HOME}/bin/sqlplus</sqlplus.app.value> <restlet.owner.value>RESTLET</restlet.owner.value> <sqlnet.string.value>test</sqlnet.string.value> <jdbc.str.value>test</jdbc.str.value> <jdbc.username.value>LUCENE</jdbc.username.value> <jdbc.password.value>LUCENE</jdbc.password.value> <jdbc.sysusr.value>sys</jdbc.sysusr.value> <jdbc.syspwd.value>change_on_install</jdbc.syspwd.value> </properties> .... sqlplus.app: using ORACLE_HOME environment variable will work in most of the installation, this parameter is used to locate Oracle SQLPlus executable application used to connect as sysdba. restlet.owner: Oracle schema where XMLDB Restlet adapter was installed. sqlnet.string: SQLNet connect string to the target database. jdbc.{username,password,sysusr,syspwd}: username/password where Lucene REST WS API will be installed, sysusr/syspwd used to connect with sysdba role to perform post installation steps. 6.24.8.7 Targets
mvn clean
Compile Lucene REST WS API implementation. First execution of this target will try to download from Maven publics repostories Oracle JDBC driver and Oracle-Lucene artifacts, this Maven's artifacts are not in public repositories you can install into your local repository as follow mvn install:install-file -DgroupId=oracle -DartifactId=ojdbc5 -Dversion=11.1.0 -Dpackaging=jar -Dfile=$ORACLE_HOME/jdbc/lib/ojdbc5.jar mvn install:install-file -DgroupId=oracle -DartifactId=xdb -Dversion=11.1.0 -Dpackaging=jar -Dfile=$ORACLE_HOME/rdbms/jlib/xdb.jar mvn install:install-file -DgroupId=org.apache.lucene -DartifactId=lucene-ojvm -Dversion=2.3.2 -Dpackaging=jar -Dfile=/home/mochoa/jdevhome/mywork/ojvm-bin/11g/ojvm/lib/lucene-ojvm-2.3.jar Restlet User Guide - Version 1.1 95
Runs JUnit test suites. By now only a simple test suite is performed, Maven requires one to create an artifact. More Restlet client side test suites will be added soon.
mvn install
Install Lucene REST WS API into the database using configurations parameters explained above. Also copy a .jar file to a local repository. Return to main document (page 82).
2008-06-19 09:24:08.039:/:INFO: UsersRestlet: [Noelios Restlet Engine] - The ServerServlet address = null 2008-06-19 09:24:08.039:/:INFO: UsersRestlet: [Noelios Restlet Engine] - The ServerServlet port = 8080 2008-06-19 09:24:08.039:/:INFO: UsersRestlet: [Noelios Restlet Engine] - The ServerServlet endpoint = 1 2008-06-19 09:24:08.039:/:INFO: UsersRestlet: [Noelios Restlet Engine] - Try to load 'org.restlet.attribute.application' parameter from '/home/'||USER||'/restlet/UsersRestlet.xml 2008-06-19 09:24:11.584:/:INFO: UsersRestlet: [Noelios Restlet Engine] - Try to load 'org.restlet.attribute.component' parameter from '/home/'||USER||'/restlet/UsersRestlet.xml 2008-06-19 09:24:11.595:/:INFO: UsersRestlet: [Noelios Restlet Engine] - Try to load 'org.restlet.component' parameter from '/home/'||USER||'/restlet/UsersRestlet.xml Jun 19, 2008 9:24:11 AM org.restlet.Connector <init> WARNING: The connector has been instantiated without any protocol. 2008-06-19 09:24:11.808:/:INFO: UsersRestlet: [Noelios Restlet Engine] - Try to load 'org.restlet.attribute.server' parameter from '/home/'||USER||'/restlet/UsersRestlet.xml 2008-06-19 09:24:11.818:/:INFO: UsersRestlet: [Noelios Restlet Engine] - Attaching application: org.apache.lucene.ws.LuceneApplication@5878d2 to URI: /lucene Jun 19, 2008 9:24:11 AM com.noelios.restlet.ext.xdb.XdbServletWarClientHelper start INFO: efective user is: LUCENE Jun 19, 2008 9:24:12 AM com.noelios.restlet.LogFilter afterHandle INFO: 2008-06-19 09:24:12 8080 GET /lucene/ 200 157 704 http://localhost:8088 Note that LUCENE user is configured in pom.xml file, so it will passed to Jetty as System properties and used by XMLDB Restlet adapter as effective user. If you will try to test LuceneApplication using telnet scripts change LUCENE/LUCENE to scott/tiger into pom.xml file. You can debug and test LuceneApplication.java using Restlet default servlet engine starting it as a simple Java application, but this scenary will not test XMLDB Restlet stack. 6.24.9.2 Testing with telnet Directory src/main/scripts have several .txt file which includes HTTP content information to test Lucene REST WS API. For example to get all Lucene Domain Indexes at SCOTT's schema you can execute: [mochoa@mochoa lucene-restlet]$ cat src/main/scripts/test_get_scott.txt GET /lucene/ HTTP/1.0 Authorization: Basic c2NvdHQ6dGlnZXI= Host: localhost:8080 [mochoa@mochoa lucene-restlet]$ telnet localhost 8080 Trying 127.0.0.1... Connected to live.dbprism.mochoa.dyndns.org (127.0.0.1). Escape character is '^]'. GET /lucene/ HTTP/1.0 Authorization: Basic c2NvdHQ6dGlnZXI= Host: localhost:8080 HTTP/1.1 200 OK MS-Author-Via: DAV DAV: 1,2,<http://www.oracle.com/xdb/webdav/props> Date: Wed, 18 Jun 2008 23:08:06 GMT Restlet User Guide - Version 1.1 97
Server: Noelios-Restlet-Engine/1.1.snapshot Content-Type: application/atomsvc+xml; charset=ISO-8859-1 Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept Content-Length: 330 Expires: Wed, 18 Jun 2008 23:08:16 GMT <?xml version="1.0" encoding="ISO-8859-1"?> <service xmlns="http://purl.org/atom/app#"> <workspace title="Lucene Web Service"> <collection href="SOURCE_BIG_LIDX/" title="Index Name: SOURCE_BIG_LIDX status: VALID"> <member-type>entry</member-type> </collection> </workspace> </service> Connection closed by foreign host. Note that the Authorization header have a B64 encoding information of scott:tiger user/password, if your database have different values it will not work. Also we are using XMLDB default HTTP port (8080). The example shows that scott have one Lucene Domain Index named SOURCE_BIG_LIDX. Th is index was created using a table and index creation SQL script like: SQL> create table test_source_big as (select * from all_source); SQL> create index source_big_lidx on test_source_big(text) indextype is lucene.LuceneIndex parameters('AutoTuneMemory:true;Analyzer:org.apache.lucene.analysis.StopAnalyzer;\ MergeFactor:500;FormatCols:line(0000);ExtraCols:line "line"'); 6.24.9.3 Testing with JMeter plugin for Maven Download and install JMeter Maven Plugin118 following this guide at http://wiki.apache.org/jakarta-jmeter/JMeterMavenPlugin Install required libraries from JMeter distribution mvn install:install-file -DgroupId=org.apache.jmeter -DartifactId=jmeter -Dversion=2.2 -Dpackaging=jar -Dfile=/home/mochoa/Download/jmeter-2.2.jar -DpomFile=/home/mochoa/Download/jmeter-2.2.pom mvn install:install-file -DgroupId=org.apache.jorphan -DartifactId=jorphan -Dversion=2.2 -Dpackaging=jar -Dfile=/usr/local/jakarta-jmeter-2.3.1/lib/jorphan.jar mvn install:install-file -DgroupId=org.mozilla.javascript -DartifactId=javascript -Dversion=1.0 -Dpackaging=jar -Dfile=/usr/local/jakarta-jmeter-2.3.1/lib/js_rhino1_6R5.jar mvn install:install-file -DgroupId=jcharts -DartifactId=jcharts -Dversion=0.7.5 -Dpackaging=jar -Dfile=/usr/local/jakarta-jmeter-2.3.1/lib/jCharts-0.7.5.jar pom.xml file modifications .... <dependency> <groupId>org.apache.jmeter</groupId> <artifactId>maven-jmeter-plugin</artifactId> <version>1.0-SNAPSHOT</version> </dependency> .... Restlet User Guide - Version 1.1 98
<plugin> <groupId>org.apache.jmeter</groupId> <artifactId>maven-jmeter-plugin</artifactId> <configuration> <includes> <include>test_get_scott.jmx</include> </includes> <reportDir>target/jmeter-reports</reportDir> </configuration> </plugin> .... running mvn org.apache.jmeter:maven-jmeter-plugin:jmeter 6.24.9.4 Measuring performance using Apache JMeter Using some of the JMeter templates at directory src/test/jmeter you can performs performance test of Lucene REST WS API over Lucene Domain Index. Here a sample screen shoot:
99
Retrieves a list of AtomPP indices introspection document Most recent modified documents Searches the index Retrieves the list of properties for the index Gets the OpenSearch Description document Gets a document from the index Atom Feed
Index121
GET
Index123 Index.Properties
125
OpenSearch Description127
GET
OSD Document
Document129 Document
GET
GET (with /mlt at Gets a list of end) document like this (More like this)
100
Document
To be implemented
Notes
1. 2. 3. 4. 5. 6. 7. 8. 9. http://www.restlet.org/documentation/1.1/faq#04 http://www.restlet.org/documentation/1.1/faq#05 http://www.atomenabled.org/developers/syndication/atom-format-spec.php http://www.atomenabled.org/developers/protocol/atom-protocol-spec.php http://commons.apache.org/fileupload/ http://www.restlet.org/documentation/1.1/ext/org/restlet/ext/fileupload/package-summary.html http://www.restlet.org/documentation/1.1/faq#18 http://java.sun.com/products/servlet/ http://jakarta.apache.org/commons/fileupload/
10. http://freemarker.org/ 11. http://www.restlet.org/documentation/1.1/ext/org/restlet/ext/freemarker/package-summary.html 12. http://www.restlet.org/documentation/1.1/faq#10 13. http://freemarker.org/ 14. https://grizzly.dev.java.net/ 15. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/grizzly/HttpsServerHelper.html 16. https://grizzly.dev.java.net/ 17. http://jakarta.apache.org/commons/httpclient/ 18. http://jakarta.apache.org/httpcomponents/httpclient-3.x/tutorial.html 19. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/httpclient/HttpClientHelper.html 20. http://jakarta.apache.org/commons/httpclient/ 21. http://jakarta.apache.org/commons/codec/ 22. http://jakarta.apache.org/commons/logging/ 23. http://java.sun.com/products/javamail/ 24. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/javamail/JavaMailClientHelper.html 25. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/javamail/JavaMailClientHelper.html 26. http://java.sun.com/products/javamail/ 27. http://java.sun.com/products/javabeans/jaf/ 28. https://jsr311.dev.java.net/ 29. http://www.restlet.org/downloads/ 30. http://www.restlet.org/documentation/1.1/firstSteps#part03 31. http://www.restlet.org/community/lists 32. http://users.informatik.haw-hamburg.de/~ubicomp/arbeiten/master/koops.pdf 33. http://java.sun.com/products/jdbc/ 34. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/jdbc/JdbcClientHelper.html 35. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/jdbc/RowSetRepresentation.html
101
36. http://jakarta.apache.org/commons/dbcp/ 37. http://jakarta.apache.org/commons/pool/ 38. http://jakarta.apache.org/commons/logging/ 39. http://www.mortbay.org/ 40. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/jetty/JettyServerHelper 41. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/jetty/HttpServerHelper 42. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/jetty/HttpsServerHelper 43. http://www.mortbay.org/ 44. http://java.sun.com/products/servlet/ 45. http://docs.codehaus.org/display/JETTY/How+to+configure+SSL 46. http://en.wikipedia.org/wiki/Apache_JServ_Protocol 47. http://tomcat.apache.org/connectors-doc/webserver_howto/apache.html 48. http://www.mortbay.org/ 49. http://docs.codehaus.org/display/JETTY/Embedding+Jetty 50. http://docs.codehaus.org/display/JETTY/Configuring+AJP13+Using+mod_jk 51. http://httpd.apache.org/docs/ 52. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/jetty/HttpServerHelper.html 53. http://www.restlet.org/documentation/1.1/api/org/restlet/Server.html 54. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/jetty/AjpServerHelper.html 55. http://jibx.sourceforge.net/ 56. http://www.json.org/ 57. http://www.restlet.org/documentation/1.1/ext/org/restlet/ext/json/package-summary.html 58. http://www.restlet.org/documentation/1.1/faq#10 59. ../../../../../../ 60. http://www.json.org/java/ 61. http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/net/HttpURLConnection.html 62. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/net/HttpClientHelper.html 63. http://www.hueniverse.com/hueniverse/2007/10/beginners-guide.html 64. http://www.hueniverse.com/hueniverse/2007/10/beginners-gui-1.html 65. http://www.hueniverse.com/hueniverse/2008/10/beginners-guide.html 66. http://www.hueniverse.com/hueniverse/2008/10/beginners-gui-1.html 67. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/servlet/package-summary.html 68. http://www.restlet.org/documentation/1.1/faq#02 69. http://java.sun.com/products/servlet/ 70. http://www.simpleframework.org/ 71. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/simple/SimpleServerHelper 72. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/simple/HttpServerHelper 73. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/simple/HttpsServerHelper 74. http://www.simpleframework.org/ 75. http://www.restlet.org/documentation/1.1/ext/org/restlet/ext/spring/package-summary.html 76. http://www.restlet.org/documentation/1.1/faq#23 77. ../../../../../../
102
78. http://www.springframework.org/ 79. ../../../../../../../ 80. http://static.springframework.org/spring/docs/2.5.x/reference/xsd-config.html#xsd-config-body-schemas-util-property-path 81. http://examples.oreilly.com/9780596529260/ 82. http://www.oreilly.com/catalog/9780596529260/ 83. http://maven.apache.org/ 84. http://www.db4o.com/ 85. http://www.db4o.com/ 86. http://www.db4o.com/ 87. https://springmodules.dev.java.net/ 88. http://www.restlet.org/documentation/1.1/nre/com/noelios/restlet/util/SslContextFactory.html 89. http://code.google.com/p/jsslutils/ 90. http://www.restlet.org/documentation/1.1/ext/com/noelios/restlet/ext/ssl/package-summary.html 91. http://velocity.apache.org/engine/ 92. http://www.restlet.org/documentation/1.1/ext/org/restlet/ext/velocity/package-summary.html 93. http://www.restlet.org/documentation/1.1/faq#10 94. http://velocity.apache.org/ 95. http://jakarta.apache.org/commons/collections 96. http://jakarta.apache.org/commons/lang 97. http://www.restlet.org/ 98. http://www.oracle.com/technology/tech/xml/xmldb/index.html 99. http://www.oracle.com/technology/tech/xml/xmldb/oow/2007/database%20native%20web%20services%20with%20oracle %20xml%20db.pdf 100. http://httpd.apache.org/docs/2.2/mod/mod_cache.html 101. http://www.oracle.com/technology/products/ias/web_cache/index.html 102. http://www.akamai.com/html/support/esi.html 103. http://www.infoq.com/news/2007/11/restful-ajax-http304 104. http://ant.apache.org/ 105. http://restlet.tigris.org/source/browse/restlet/ 106. http://www.restlet.org/downloads/snapshot.zip 107. http://spreadsheets.google.com/pub?key=pAl-EJ5Wtb_10aTyfnO1dUw 108. http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28369/xdb_web_services.htm#CHDDBCHB 109. http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28369/xdb22pro.htm#CHDHAGBF 110. http://forums.oracle.com/forums/thread.jspa?threadID=336855&start=30&tstart=0 111. http://docs.google.com/View?docid=ddgw7sjp_54fgj9kg 112. http://marceloochoa.blogspot.com/2007/09/running-lucene-inside-your-oracle-jvm.html 113. http://lucene.apache.org/java/docs/index.html 114. http://dev.lucene-ws.net/wiki/API 115. http://downloads.sourceforge.net/dbprism/lucene-restlet-0.9.0.zip?download 116. http://downloads.sourceforge.net/dbprism/lucene-restlet-0.9.0.tar.gz?download 117. http://downloads.sourceforge.net/dbprism/ojvm-bin-11g-2.3.2.0.0.jar?download 118. http://wiki.apache.org/jakarta-jmeter/JMeterMavenPlugin
103
119. http://dev.lucene-ws.net/wiki/ServiceAPI#GET 120. http://dbprism.cvs.sourceforge.net/dbprism/lucene-restlet/src/main/java/org/apache/lucene/ws/IndexesResource.java?view=l og 121. http://dev.lucene-ws.net/wiki/IndexAPI#GET 122. http://dbprism.cvs.sourceforge.net/dbprism/lucene-restlet/src/main/java/org/apache/lucene/ws/IndexResource.java?view=log 123. http://dev.lucene-ws.net/wiki/IndexSearchAPI#GETwithquery 124. http://dbprism.cvs.sourceforge.net/dbprism/lucene-restlet/src/main/java/org/apache/lucene/ws/QueryResource.java?view=lo g 125. http://dev.lucene-ws.net/wiki/IndexPropertiesAPI#GET 126. http://dbprism.cvs.sourceforge.net/dbprism/lucene-restlet/src/main/java/org/apache/lucene/ws/IndexProperty.java?view=log 127. http://dev.lucene-ws.net/wiki/IndexSearchAPI#GETopensearchdescription.xml 128. http://dbprism.cvs.sourceforge.net/dbprism/lucene-restlet/src/main/java/org/apache/lucene/ws/IndexOpenSearch.java?view=l og 129. http://dev.lucene-ws.net/wiki/DocumentAPI#GET 130. http://dbprism.cvs.sourceforge.net/dbprism/lucene-restlet/src/main/java/org/apache/lucene/ws/DocumentResource.java?view =log
104
7 Restlet-GWT module
7.1 Introduction
This chapter presents the Restlet-GWT module, which is a port of the client side Restlet API to GWT 1.5.
7.2 Description
Google Web Toolkit is a powerful and widely used platform for rich internet application. It is based on a smart compiler taking Java source and producing optimized JavaScript (byte)code. By default, GWT recommends using a custom GWT-RPC mechanism to communicate between the GWT front-end (Web browser) and the back-end (Web server). In addition, the back-end has to be built using a Servlet container in order to work properly and to invoke your custom classes and methods. This might remind you of the RMI (Remote Method Invocation) or CORBA mechanisms and it comes with the same issues: the tight coupling between client and server code. Also, this reduces the opportunities of integration with other back-end technologies, outside Java/Servlet. As you know, REST is a much more flexible and interoperable way to communicate between a client and a server. On the server-side, you can use Restlet or alternative technologies. But on the GWT front-end, the support has been limited so far. The GWT API does contain classes to send HTTP requests but they are quite low-level (you need to understand the HTTP headers syntax for example) and slow down productivity. Thanks to the new GWT 1.5 release, it was possible to quickly port the Restlet API and Engine to GWT. We kept only the classes required for the client-side obviously and had to remove classes based on Java APIs not available in GWT (such as NIO channels or BIO streams). We tried to provide an easy integration with JSON and XML as they are the two most common media types to exchange representations in REST for rich clients.
105
7.3 Architecture flexibility 7.3.1 Introduction 7.3.2 GWT's idiomatic RPC approach
Figure 1. (For comparison) GWT's idiomatic RPC approach requires a Servlet container and communicates opaquely via JSON-encoded data atoms. Alternatives involve writing low-level HTTP code.
Figure 2. The client-side Restlet-GWT module (org.restlet.gwt) plugs into your Google Web Toolkit code as a module, and allows you to use the high level Restlet API to talk to any server platform. XML and JSON representations are supported by default, and of course you can develop your own representational abstractions as well. Code written for Restlet should be simple to port to Restlet-GWT.
106
Figure 3. Restlet-GWT can work alongside GWT-RPC and other mechanisms. REST APIs exposed by your custom Servlets can work alongside GWT-RPC in a Servlet container environment.
Figure 4. . Not only does Restlet provide a simple means of defining and mapping REST resources, it also provides useful facilities like the Redirector, which can be used to gateway requests to other servers, easily working around the single-source limitations of the AJAX programming model. The Restlet server-side library even works in GWT Hosted Mode using the Noelios GWT Extension, so your entire application can be readily debugged.
Figure 5. If you don't need to use the Servlet-dependent GWT-RPC API, your compiled GWT application can be deployed very efficiently in a standalone Restlet environment using one of the embedded server connectors. Restlet 1.1's Net server connector, for example, has no dependencies other than Java; with this, it is possible to create and release an extremely small, but very full featured, standalone application.
107
This will make the Restlet-GWT API available to your GWT compiled code. The Restlet-GWT module in turn inherits the GWT standard HTTP2, JSON3, and XML4 modules. You can also check the full Javadocs of the API online5.
For application, supply the name of your Restlet Application, e.g. org.restlet.test.gwt.server.TestApplication. You can also supply a component via an org.restlet.component parameter, or any other permitted ServerServlet configuration parameter.
108
The module should be the name of your GWT module as seen in the hosted mode URI path. This is the package name plus the base filename of your GWT module file, e.g. org.restlet.test.gwt.TestClient. The web.xml file can be overwritten by GWT Hosted Mode in some situations. If your Restlet server side functionality fails and you start receiving messages about server requests being incorrectly dispatched to an unknown module, check that the web.xml file still contains valid contents.
109
to start a small Java Web server on port 8888, which you can visit to access a compiled GWT application that, in turn, talks to the Web server. You can also run the application in GWT Hosted Mode under Eclipse by using the included SimpleExample.launch configuration; right click this and choose Run As ... SimpleExample. It is structured as an Eclipse project; you should be able to import it into your Eclipse 3.3 or better workspace. You can also run the ant build script directly to produce the executable. You must supply your own GWT 1.5 binaries; update the Eclipse build path and/or the GWT_HOME property in the ant build script to point to the GWT binaries for your platform. 7.6.1.1 Zip content Name src Description Source files of both: client page developped with GWT and Restlet, in package "org.restlet.example.gwt.client". Web server application developped with Restlet that serves the compiled web page and hosts a resource requested from the Web page.
build.xml
Ant script that: compiles the GWT page produces a final JAR file (RestletGWTSimpleExample.jar") of the server code in directory "dist". It also includes the "/etc/manifest.mf" file.
Final directory where is located the final JAR of the server code. Directory where is located the "MANIFEST.MF" file of the server final JAR. Libraries taken from the Restlet framework (server and client APIs and implementations, GWT integration, servlet integration). Gathers configuration files for running the sample application inside Tomcat. Used to run the application in GWT Hosted Mode under Eclipse; right click this and choose "Run As ... SimpleExample". Read it!
tomcat SimpleExample.launch
README.txt
110
7.6.2 Description
7.6.2.1 GWT page You can find the source code of this page in directory "src/org/restlet/example/gwt/client". Once the server is running, this page can be accessed at the following URL: "http://localhost:8888/SimpleExample.html" . This page is in charge to display several sample item such image, button, etc organized in panels. All of these objects are instances of GWT classes:
// Define an image Image img = new Image("http://code.google.com/webtoolkit/logo-185x175.png"); // Define a button final Button button = new Button("Click me"); [...] // Define a panel VerticalPanel vPanel = new VerticalPanel(); // We can add style names. vPanel.addStyleName("widePanel"); vPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER); // Add image, button, tree vPanel.add(img); vPanel.add(button);
These class illustrates also how to add an asynchronous call with AJAX inside the final Web page. It is as simple as to use a simple Restlet client in order to request the "ping" resource located at URL '"http://localhost:8888/ping" :
final Client client = new Client(Protocol.HTTP); client.get("http://localhost:8888/ping", new Callback() { @Override public void onEvent(Request request, Response response) { button.setText(response.getEntity().getText()); } });
7.6.2.2 Server side Basically, the server s responsible to serve the generated page, and to respond to asynchronous call described just above. The generated page is served by a simple Directory Restlet from the "bin" directory when the server is run under Eclipse. The asynchronous call is delegated to the PingResource class which inherits from the Restlet Resource class. It simply answers to requests with a line of text.
@Override public Representation represent(Variant variant) throws ResourceException { return new StringRepresentation( "The Restlet server side is alive. Method called: " + getRequest().getMethod(), MediaType.TEXT_PLAIN); }
111
112
113
} } });
Notes
1. 2. 3. 4. 5. 6. 7. 8. http://code.google.com/webtoolkit/gettingstarted.html http://google-web-toolkit.googlecode.com/svn/javadoc/1.4/com/google/gwt/http/client/package-summary.html http://google-web-toolkit.googlecode.com/svn/javadoc/1.4/com/google/gwt/json/client/package-summary.html http://google-web-toolkit.googlecode.com/svn/javadoc/1.4/com/google/gwt/xml/client/package-summary.html http://www.restlet.org/documentation/snapshot/gwt/ http://www.restlet.org/documentation/snapshot/ext/com/noelios/restlet/ext/gwt/GwtShellServletWrapper.html http://www.restlet.org/documentation/snapshot/ext/com/noelios/restlet/ext/gwt/package-summary.html http://www.restlet.org/documentation/snapshot/ext/com/noelios/restlet/ext/servlet/ServerServlet.html
114
8 Best practices
In this chapter we try to collect various best practices that emerge during discussion in the Restlet mailing list or elsewhere.
8.1 Templating
When compared to the Servlet API, the Restlet API doesn't have a sister API like Java Server Pages (JSP). Instead we made the design choice to be equally open to all presentation tech nologies. This openess is materialized in the Representation class which is used for result entities. More concretely, we provide several integrations with the two popular template engines : FreeMarker and Apache Velocity. In addition, integration with Facelets has been achieved by a third party and it should be very easy to support any other reusable template technology. The design idea is to use a TemplateRepresentation that will combine at generation time a data model with a template document.
8.2.2 Tools
Regarding protocol debugging, we recommand the you install tools such as: cURL1 : command line HTTP client for Unix WireShark2 : advanced network analyzer working at the IP or TCP or HTTP levels Poster3 : FireFox extension to test RESTful Web applications etc. 115
8.4.2.1 DB4OSimpler.Class It's very clean from its name that it works as db4o function simpler.Its generalOperate method handles general operation with db4o: Restlet User Guide - Version 1.1 116
Note:This class works as only non-concurrent model,because it doesn't work as client/server model19.If you have requirement,you should modify it in concurrent(client/server) model by using Db4o.openServer method20.
package com.bjinfotech.util;
import com.db4o.Db4o; import com.db4o.ObjectContainer; import com.db4o.query.Query; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.commons.beanutils.*; /** * It's very clean from its name that it works as db4o function simpler. * Its generalOperate method handles general operation with db4o. * @author cleverpig * */ public class DB4OSimpler { //operation constants that will be used as generalOperate method's param public static final int OPERATION_SAVE=0; public static final int OPERATION_LOAD=1; public static final int OPERATION_UPDATE=2; public static final int OPERATION_DELETE=3; public static final int OPERATION_QUERY=4; public static final int OPERATION_LIST=5; public static final int OPERATION_CLEAR=6; /** * perform general Operation * @param fileName * @param op_code corresponding integer type constant * @param example object which is needed in operation * @param keyFieldName object's key field name * @return */ public static Object generalOperate( String fileName, int op_code, Object example, String keyFieldName){ Object ret=null; //open db4o file to get ObjectContainer ObjectContainer db=Db4o.openFile(fileName); Iterator iter=null; List list=null; Query query=null; try{ //perform operation according to op_code param value switch(op_code){
117
case OPERATION_SAVE: //just set!It's very simple! db.set(example); ret=example; break; case OPERATION_LOAD: //just get! list=db.get(example); if (list!=null && list.size()>0){ ret=list.get(0); } break; case OPERATION_UPDATE: //at first,I find objects which will be updated with its key field value query=db.query(); query.constrain(example.getClass()); query.descend(keyFieldName) .constrain(BeanUtils.getProperty(example, keyFieldName)); iter=query.execute().listIterator(); //and then delete all of them while(iter.hasNext()){ db.delete(iter.next()); } //set new one,now! db.set(example); ret=example; break; case OPERATION_DELETE: //just like update process:find firstly,and then delete them query=db.query(); query.constrain(example.getClass()); query.descend(keyFieldName) .constrain(BeanUtils.getProperty(example, keyFieldName)); iter=query.execute().listIterator(); if (iter.hasNext()){ while(iter.hasNext()){ db.delete(iter.next()); } ret=true; } else{ ret=false; } break; case OPERATION_QUERY: //just like update process:find firstly,and then return them query=db.query(); query.constrain(example.getClass()); query.descend(keyFieldName) .constrain(BeanUtils.getProperty(example, keyFieldName)); iter=query.execute().listIterator();
118
list=new ArrayList(); while(iter.hasNext()){ list.add(iter.next()); } if (list.size()>0) ret=list; break; case OPERATION_LIST: //return list of object which class is example.class. list=new ArrayList(); iter=db.query(example.getClass()).listIterator(); while(iter.hasNext()){ list.add(iter.next()); } if (list.size()>0) ret=list; break; case OPERATION_CLEAR: //delete anything which class is example.class. iter=db.query(example.getClass()).listIterator(); int deleteCount=0; while(iter.hasNext()){ db.delete(iter.next()); deleteCount++; }; ret=true; break; } //commit,finally db.commit(); } catch(Exception ex){ db.rollback(); ex.printStackTrace(); } finally{ db.close(); } return ret; } }
8.4.2.2 MicroblogApplication.Class It's a restful Micoblog Server which serves static files and resource(MicroblogResource) and exposes some services(static html and Microblog): Note:I used TunnelService replacing custom finder,'cause I think TunnelService is easy for using.But I'd discuss how to using custom finder to implement same function.
119
package com.bjinfotech.restlet.practice.demo.microblog;
import org.restlet.Application; import org.restlet.Component; import org.restlet.Directory; import org.restlet.Restlet; import org.restlet.Router; import org.restlet.data.Protocol;
/** * restful server * it serves static files and resource * @author cleverpig * */ public class MicroblogApplication { public static void main(String[] argv) throws Exception{ Component component=new Component(); //add http protocol component.getServers().add(Protocol.HTTP,8182); //add file protocol for accessing static web files in some directories component.getClients().add(Protocol.FILE);
Application application=new Application(component.getContext()){ @Override public Restlet createRoot(){ //directory where static web files live final String DIR_ROOT_URI="file:///E:/eclipse3.1RC3/workspace/RestletPractice/static_files/"; //create router Router router=new Router(getContext()); //attach static web files to "www" folder Directory dir=new Directory(getContext(),DIR_ROOT_URI); dir.setListingAllowed(true); dir.setDeeplyAccessible(true); dir.setNegotiateContent(true); router.attach("/www/",dir); //attach resource class:MicroblogResource to "/restful/blog" as web service URI router.attach("/restful/blog",MicroblogResource.class); return router; } }; //use TunnelService to simplify request's dispatching application.getTunnelService().setEnabled(true); application.getTunnelService().setMethodTunnel(true); application.getTunnelService().setMethodParameter("method"); //attach application component.getDefaultHost().attach(application); component.start(); } }
120
8.4.2.3 microblogAppInterface.js This is a JavaScript file used in microblog.html file,it call functions which was exposed in server side:
var SAVE_MODEL=1; var UPDATE_MODEL=2;
function switchEditorModel(model){ switch(model){ case SAVE_MODEL: Element.show('save_button'); Element.hide('update_button'); Element.hide('remove_button'); Element.hide('new_button'); break; case UPDATE_MODEL: Element.hide('save_button'); Element.show('update_button'); Element.show('remove_button'); Element.show('new_button'); break; } }
...
Event.observe( 'save_button', 'click', function(){ var formObj=Form.serialize('edit_form',true); var xmlHttp = new Ajax.Request( "/restful/blog?method=PUT", { method: 'post', parameters: 'json='+encodeURIComponent(Object.toJSON(formObj)), onComplete: function(transport){ var retObj=transport.responseText.evalJSON(); if (retObj.subject){ alert('ok,"'+retObj.subject+'" was saved!'); refreshBloglist(); switchEditorModel(UPDATE_MODEL); } } } ); }, false );
121
...
function refreshBloglist(){ var xmlHttp = new Ajax.Request( "/restful/blog", { method: 'get', parameters: '', onComplete: function(transport){ var retObjs=transport.responseText.evalJSON(); if (retObjs.length && retObjs.length>0){ var listRepr='<ul>\n'; retObjs.each(function(obj,index){ if (index<retobjs.length-1 ) listrepr+=" <li>"><a href="javascript:load(\''+obj.subject+'\');">'+obj.subject+'</a>\n'; }); listRepr+="<\ul>\n"; $('blogList').innerHTML=listRepr; } else{ $('blogList').innerHTML='Here is empty'; } } } ); } function load(subject){ var xmlHttp = new Ajax.Request( "/restful/blog", { method: 'get', parameters: 'subject='+encodeURIComponent(subject), onComplete: function(transport){ var retObj=transport.responseText.evalJSON(); if (retObj.subject){ $('subject').value=retObj.subject; $('content').value=retObj.content; $('tags').value=retObj.tags; alert('ok,"'+retObj.subject+'" was loaded!'); switchEditorModel(UPDATE_MODEL); } } } ); }
8.4.2.4 MicroblogResource.Class
package com.bjinfotech.restlet.practice.demo.microblog;
import java.util.List;
122
import java.util.logging.Logger;
import org.restlet.Context; import org.restlet.data.CharacterSet; import org.restlet.data.Form; import org.restlet.data.Language; import org.restlet.data.MediaType; import org.restlet.data.Request; import org.restlet.data.Response; import org.restlet.resource.Representation; import org.restlet.resource.Resource; import org.restlet.resource.ResourceException; import org.restlet.resource.StringRepresentation; import org.restlet.resource.Variant; import org.restlet.data.Status; import com.bjinfotech.util.JSONSimpler; import com.bjinfotech.util.Utils;
public class MicroblogResource extends Resource { Logger log=Logger.getLogger(MicroblogResource.class.getSimpleName()); //MicroblogPersistenceManager MicroblogPersistenceManager micoblogPM=new MicroblogPersistenceManager(); //StringRepresentation constant final StringRepresentation NO_FOUND_REPR=new StringRepresentation("No found!"); final StringRepresentation ERR_REPR=new StringRepresentation("something wrong!"); //json param name in request final String JSON_PARAM="json";
public MicroblogResource( Context context, Request request, Response response) { super(context, request, response); this.getVariants().add(new Variant(MediaType.TEXT_PLAIN)); //it's important,please don't forget it. this.setAvailable(true); this.setModifiable(true); this.setNegotiateContent(true); } @Override /** * representing after calling default get handle * @param variant */ public Representation represent(Variant variant) throws ResourceException{ log.info("representing after calling default get handle..."); Representation result = null; if (variant.getMediaType().equals(MediaType.TEXT_PLAIN)) { //find "subject" param in request,"subject" param is tranformed from web client.it means load one blog with special subject
123
String subject=getRequest().getResourceRef().getQueryAsForm().getFirstValue("subject"); log.info("subject:"+subject); //handle query if (subject!=null && subject.length()>0){ //find blog with special subject Microblog example=new Microblog(); example.setSubject(subject); List queryRet=micoblogPM.query(example); //return result in JSON format StringRepresentation if (queryRet!=null && queryRet.size()>0){ result=new StringRepresentation( JSONSimpler.serializeFromBean(queryRet.get(0)), MediaType.APPLICATION_JSON, Language.ALL, CharacterSet.UTF_8 ); } else{ result=NO_FOUND_REPR; } } else{ //return blog list in JSON format StringRepresentation result=new StringRepresentation( JSONSimpler.serializeFromBeanList(micoblogPM.list()), MediaType.APPLICATION_JSON, Language.ALL, CharacterSet.UTF_8 ); } } return result; } /** * call MicroblogPersistenceManager's method excluding query and list,just save/update/delete. * @param method method name * @param jsonParamVal json param value coming from request * @return */ protected StringRepresentation callMethod(String method,String jsonParamVal){ //transform json format string to Microblog object Microblog microblog=(Microblog)JSONSimpler.deserializeToBean(jsonParamVal,Microblog.class); if (microblog!=null){ //call method and gain json format string as responseText String responseText=Utils.callMethodAndGainResponseJSONStr( micoblogPM, method, jsonParamVal,
124
Microblog.class); log.info("response:"+responseText); //return json StringRepresentation return new StringRepresentation( responseText, MediaType.APPLICATION_JSON, Language.ALL, CharacterSet.UTF_8 ); } else{ return ERR_REPR; } } @Override /** * handling post in high level * @param entity */ public void acceptRepresentation(Representation entity) throws ResourceException{ log.info("handling post in high level..."); super.acceptRepresentation(entity); getResponse().setStatus(Status.SUCCESS_OK); Form f = new Form(entity); String jsonParamVal=f.getValues(JSON_PARAM); log.info("json param:"+jsonParamVal); //call update and set response getResponse().setEntity(callMethod("update",jsonParamVal)); } @Override /** * handling put in high level * @param entity */ public void storeRepresentation(Representation entity) throws ResourceException{ log.info("handling put in high level..."); super.storeRepresentation(entity); getResponse().setStatus(Status.SUCCESS_CREATED); Form f = new Form(entity); String jsonParamVal=f.getValues(JSON_PARAM); log.info("json param:"+jsonParamVal); //call save and set response getResponse().setEntity(callMethod("save",jsonParamVal)); } @Override /** * handling delete in high level * @param entity */ public void removeRepresentations() throws ResourceException{
125
log.info("handling delete in high level..."); super.removeRepresentations(); getResponse().setStatus(Status.SUCCESS_OK); Form f = getRequest().getEntityAsForm(); String jsonParamVal=f.getValues(JSON_PARAM); log.info("json param:"+jsonParamVal); //call delete and set response getResponse().setEntity(callMethod("delete",jsonParamVal)); } }
8.4.2.5 Microblog.Class package com.bjinfotech.restlet.practice.demo.microblog; public class Microblog { private String subject; private String content; private String tags; public String getSubject() { return subject; } ... }
126
Custom Finder:
public class PrototypeFinder extends Finder { public targetClass) { super(context, targetClass); } PrototypeFinder(Context context, Class
127
public void handle(Request request, Response response) { //get "_method" param value
Parameter p = request.getEntityAsForm().getFirst("_method"); //reset requst method accoring "_method" param value request.setMethod(null != p ? Method.valueOf(p.getValue()) : request.getMethod()); super.handle(request, response); } }
function callJSON() { new Ajax.Request('/ajax', { parameters: 'name=PUT', method: 'put', putBody: "PUT BODY", onComplete: function (transport) { alert(transport.responseText); } }); new Ajax.Request('/ajax', { parameters: 'name=POST', method: 'post', onComplete: function (transport) { alert(transport.responseText); } }); new Ajax.Request('/ajax', { parameters: 'name=DELETE', method: 'delete', onComplete: function (transport) { alert(transport.responseText); } }); }
...
8.4.6 Thanks
Evgeny Shepelyuk:this guy gave me a lot of good advice!
Notes
1. 2. 3. 4. http://curl.haxx.se/ http://www.wireshark.org/ http://code.google.com/p/poster-extension/ http://blog.arc90.com/2008/06/building_restful_web_apps_groovy_restlet_part_1.php
128
5. 6. 7. 8. 9.
10. http://www.xfront.com/REST-Web-Services.html 11. http://www.xfront.com/REST-Web-Services.html 12. http://www.restlet.org/documentation/1.1/api/index.html 13. http://www.restlet.org/documentation/1.1/tutorial 14. http://db4o.com/about/productinformation/resources/db4o-6.3-tutorial-java.pdf 15. http://www.prototypejs.org/learn/json 16. http://www.restlet.org/documentation/1.1/api/org/restlet/Application.html 17. http://www.restlet.org/documentation/1.1/api/org/restlet/Router.html 18. http://www.restlet.org/documentation/1.1/api/org/restlet/resource/Resource.html 19. http://developer.db4o.com/resources/api/db4o-java/com/db4o/Db4o.html 20. http://developer.db4o.com/resources/api/db4o-java/com/db4o/Db4o.html#openServer(java.lang.String,%20int)
129
9 Examples
9.1 Introduction
This chapter contains some concrete usage examples of the Restlet framework.
9.2 Description
The first example describe the way the Restlet.org and other sister Web sites are configured. There is also a link to examples from the famous O'Reilly book on REST that were ported to Restlet. If you are looking for more, remember to check the source code shipped in the Restlet distribution as it contains many examples in the "org.restlet.example" module.
9.3.2 Introduction
The Restlet web site that you are currently navigating is powered by the Noelios Restlet Engine, the reference implementation of the Restlet API. In order to serve HTTP calls, we rely on a production-ready Simple 3.1 HTTP connector. As you will see below, running basic web sites with Restlets is very simple.
130
131
132
// -----------------host = new VirtualHost(getContext()); host.setHostDomain("search.restlet.org|localhost"); host.setHostPort("80|" + Integer.toString(port)); host.attach(new SearchRestletOrg(getContext(), wwwUri + "/search-restlet-org", redirectUri)); getHosts().add(host); // --------------// www.restlet.net // --------------host = new VirtualHost(getContext()); host.setHostDomain("www.restlet.net"); host.setHostPort("80|" + Integer.toString(port)); host.attach(new RedirectApplication(getContext(), "http://restlet.tigris.org{rr}", false)); host.attach("/fisheye/", new RedirectApplication(getContext(), "http://fisheye3.cenqua.com/browse/restlet/{rr}", false)); getHosts().add(host); // --------------// www.noelios.com // --------------host = new VirtualHost(getContext()); host.setHostDomain("www.noelios.com"); host.setHostPort("80|" + Integer.toString(port)); host.attach(new WwwNoeliosCom(getContext(), dataUri, wwwUri + "/www-noelios-com", login, password)); getHosts().add(host); // --------------------------// Redirect to www.noelios.com // --------------------------host = new VirtualHost(getContext()); host.setHostDomain("noelios.com|noelios.net|noelios.org|" + "www.noelios.net|www.noelios.org"); host.setHostPort("80|" + Integer.toString(port)); host.attach(new RedirectApplication(getContext(), "http://www.noelios.com{rr}", true)); getHosts().add(host); }
133
* Indicates if the redirection is permanent or temporary. */ public RedirectApplication(Context parentContext, String targetUri, boolean permanent) { super(parentContext); this.targetUri = targetUri; this.permanent = permanent; } @Override public String getName() { return "Redirection application"; } @Override public Restlet createRoot() { int mode = (this.permanent) ? Redirector.MODE_CLIENT_PERMANENT : Redirector.MODE_CLIENT_TEMPORARY; return new Redirector(getContext(), this.targetUri, mode); } }
9.3.8 Conclusion
In term of coding, that's about all that we use. In addition, we configure standard JDK logging properties in order to write a web log file based on the applications' log services that write to the "com.noelios.web.WebComponent.www" logger. Finally, we also rely on the Java Service Wrapper tool to execute our component as a Linux daemon. Thanks to Michael Mayer for the idea of providing the source code of this web site as a sample application.
Notes
1. 2. http://www.restlet.org/documentation/books#restful-web-services http://www.restlet.org/documentation/1.1/examples/books/rest/src.zip
134
10 Glossary
10.2 Application
Restlet that can be attached to one or more VirtualHosts. Applications are guaranteed to receive calls with their base reference set relatively to the VirtualHost that served them. This class is both a descriptor able to create the root Restlet and the actual Restlet that can be attached to one or more VirtualHost instances. Restlet User Guide - Version 1.1 135
10.3 Client
Connector acting as a generic client. It internally uses one of the available connectors registered with the current Restlet implementation.
10.4 Component
Restlet managing a set of Clients, Servers and other Restlets. "A component is an abstract unit of software instructions and internal state that provides a transformation of data via its interface." Roy T. Fielding Component managing a set of VirtualHosts and Applications. Applications are expected to be directly attached to VirtualHosts. Components are also exposing a number of services in order to control several operational features in a portable way, like access log and status setting.
10.5 Connector
Restlet enabling communication between Components. "A connector is an abstract mechanism that mediates communication, coordination, or cooperation among components. Connectors enable communication between components by transferring data elements from one interface to another without changing the data." Roy T. Fielding "Encapsulate the activities of accessing resources and transferring resource representations. The connectors present an abstract interface for component communication, enhancing simplicity by providing a clean separation of concerns and hiding the underlying implementation of resources and communication mechanisms." Roy T. Fielding
10.6 Context
Contextual data and services provided to a Restlet. The context is the means by which a Restlet may access the software environment within the framework. It is typically provided by the immediate parent Restlet (Component and Application are the most common cases). The services provided are access to a logger, access to configuration parameters and to a request dispatcher.
10.7 Directory
Handler mapping a directory of local resources. Those resources have representations accessed b y the file system, the WAR context or the class loaders. An automatic content negotiation mechanism (similar to the one in Apache HTTP server) is used to select the best representation of a resource based on the available variants and on the client capabilities and preferences.
10.8 Engine
A Restlet Engine is an implementation of the Restlet API. The reference implementation, provided by Noelios Technologies, is therefore called the Noelios Restlet Engine (NRE).
136
10.9 Filter
Restlet filtering calls before passing them to an attached Restlet. The purpose is to do some pre-processing or post-processing on the calls going through it before or after they are actually handled by an attached Restlet. Also note that you can attach and detach targets while handling incoming calls as the filter is ensured to be thread-safe.
10.10 Finder
Restlet that can find the target resource that will concretely handle the request. Based on a given resource class, it is also able to instantiate the resource with the call's context, request and response without requiring the usage of a subclass. Once the target resource has been found, the call is automatically dispatched to the appropriate handle*() method (where the '*' character corresponds to the method name) if the corresponding allow*() method returns true. For example, if you want to support a MOVE method for a WebDAV server, you just have to add a handleMove() method in your subclass of Resource and it will be automatically be used by the Finder instance at runtime. If no matching handle*() method is found, then a Status.CLIENT_ERROR_METHOD_NOT_ALLOWED is returned.
10.11 Guard
Filter guarding the access to an attached Restlet.
10.12 Redirector
Rewrites URIs then redirects the call or the client to a new destination.
10.13 Representation
Current or intended state of a resource. For performance purpose, it is essential that a minimal overhead occurs upon initialization. The main overhead must only occur during invocation of content processing methods (write, getStream, getChannel and toString).Current or intended state of a resource. "REST components perform actions on a resource by using a representation to capture the current or intended state of that resource and transferring that representation between components. A representation is a sequence of bytes, plus representation metadata to describe those bytes. Other commonly used but less precise names for a representation include: document, file, and HTTP message entity, instance, or variant." Roy T. Fielding
10.14 Request
Generic request sent by client connectors. It is then received by server connectors and processed by Restlets. This request can also be processed by a chain of Restlets, on the client or server sides. Requests are uniform across all types of connectors, protocols and components.
137
10.15 Resource
Intended conceptual target of a hypertext reference. "Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource." "The only thing that is required to be static for a resource is the semantics of the mapping, since the semantics is what distinguishes one resource from another." Roy T. Fielding Another definition adapted from the URI standard (RFC 3986): a resource is the conceptual mapping to a representation (also known as entity) or set of representations, not necessarily the representation which corresponds to that mapping at any particular instance in time. Thus, a resource can remain constant even when its content (the representations to which it currently corresponds) changes over time, provided that the conceptual mapping is not changed in the process. In addition, a resource is always identified by a URI.
10.16 Response
Generic response sent by server connectors. It is then received by client connectors. Responses are uniform across all types of connectors, protocols and components.
10.17 Restlet
Dispatcher that provides a context and life cycle support.
10.18 Route
Filter scoring the affinity of calls with the attached Restlet. The score is used by an associated Router in order to determine the most appropriate Restlet for a given call.
10.19 Router
Restlet routing calls to one of the attached routes. Each route can compute an affinity score for each call depending on various criteria. The attach() method allow the creation of routes based on URI patterns matching the beginning of a the resource reference's remaining part. In addition, several routing modes are supported, implementing various algorithms: Best match (default) First match Last match Random match Round robin Custom
138
Note that for routes using URI patterns will update the resource reference's base reference during the routing if they are selected. If you are using hierarchical paths, remember to directly attach the child routers to their parent router instead of the top level Restlet component. Also, remember to manually handle the path separator characters in your path patterns otherwise the delegation will not work as expected. Finally, you can modify the routes list while handling incoming calls as the delegation code is ensured to be thread-safe.
10.20 Server
Connector acting as a generic server. It internally uses one of the available connectors registered with the current Restlet implementation.
10.21 Transformer
Filter that can transform XML representations by applying an XSLT transform sheet.
10.22 Uniform
Base class exposing a uniform REST interface. "The central feature that distinguishes the REST architectural style from other network-based styles is its emphasis on a uniform interface between components. By applying the software engineering principle of generality to the component interface, the overall system architecture is simplified and the visibility of interactions is improved. Implementations are decoupled from the services they provide, which encourages independent evolvability." Roy T. Fielding It has many subclasses that focus on a specific ways to handle calls like filtering, routing or finding a target resource. The context property is typically provided by a parent component as a way to give access to features such as logging and client connectors.
139