View Javadoc
1   package ejava.examples.ejbwar.inventory.client;
2   
3   import java.net.URI;
4   
5   import java.util.ArrayList;
6   import java.util.List;
7   
8   import javax.ws.rs.core.HttpHeaders;
9   import javax.ws.rs.core.MediaType;
10  import javax.ws.rs.core.Response;
11  import javax.ws.rs.core.UriBuilder;
12  
13  import org.apache.commons.logging.Log;
14  import org.apache.commons.logging.LogFactory;
15  import org.apache.http.HttpResponse;
16  import org.apache.http.NameValuePair;
17  import org.apache.http.client.HttpClient;
18  import org.apache.http.client.entity.UrlEncodedFormEntity;
19  import org.apache.http.client.methods.HttpDelete;
20  import org.apache.http.client.methods.HttpGet;
21  import org.apache.http.client.methods.HttpPost;
22  import org.apache.http.client.methods.HttpPut;
23  import org.apache.http.entity.StringEntity;
24  import org.apache.http.message.BasicNameValuePair;
25  import org.apache.http.util.EntityUtils;
26  
27  import ejava.examples.ejbwar.inventory.bo.Categories;
28  import ejava.examples.ejbwar.inventory.bo.Category;
29  import ejava.examples.ejbwar.inventory.bo.InventoryRepresentation;
30  import ejava.examples.ejbwar.inventory.bo.Product;
31  import ejava.examples.ejbwar.inventory.bo.Products;
32  import ejava.examples.ejbwar.inventory.rs.CategoriesResource;
33  import ejava.examples.ejbwar.inventory.rs.ProductsResource;
34  
35  /**
36   * This class implements an HTTP Client interface to the inventory 
37   * web application. All commands are through HTTP POST, GET, PUT, and DELETE
38   * methods to specific resource URIs for products and categories.
39   */
40  public class InventoryClientImpl implements InventoryClient {
41  	private static final Log log = LogFactory.getLog(InventoryClientImpl.class);
42  	private HttpClient client;
43  	/**
44  	 * Defines the HTTP URL for the WAR that hosts the JAX-RS resources.
45  	 */
46  	private URI appURI;
47  
48  	public void setHttpClient(HttpClient client) {
49  		this.client = client;
50  	}
51  	public void setAppURI(URI appURI) {
52  		this.appURI = appURI;
53  	}	
54  	
55  	/**
56  	 * Helper method that returns a URIBuilder fully initialized to point
57  	 * to the URI that will reach the specified method within the inventory
58  	 * resource classes.
59  	 * @param resourceClass
60  	 * @param method
61  	 * @return
62  	 */
63  	protected <T> UriBuilder buildURI(Class<T> resourceClass, String method) {
64  		//start with the URI for the WAR deployed to the server 
65  		//that ends with the context-root
66  		return UriBuilder.fromUri(appURI)
67  				//add path info from the 
68  				//javax.ws.rs.core.Application @ApplicationPath
69  				.path("rest")
70  				//add in @Path added by resource class
71  				.path(resourceClass)
72  				//add in @Path added by resource class' method
73  				.path(resourceClass,method);
74  				//the result will be a URI template that 
75  				//must be passed arguments by the caller during build()
76  	}
77  	
78  	@Override
79  	public Categories findCategoryByName(String name, int offset, int limit) throws Exception {
80  		//build a URI to the specific method that is hosted within the app
81  		URI uri = buildURI(CategoriesResource.class,"findCategoriesByName")
82  				//marshall @QueryParams into URI
83  				.queryParam("name", name)
84  				.queryParam("offset", offset)
85  				.queryParam("limit", limit)
86  				.build();
87  		
88  		//build the overall request 
89  		HttpGet get = new HttpGet(uri);
90  		get.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML);
91  		
92  		//issue request and look for an OK response with entity
93  		HttpResponse response = client.execute(get);
94  		log.info(String.format("%s %s", get.getURI(), response));
95  		if (Response.Status.OK.getStatusCode() == response.getStatusLine().getStatusCode()) {
96  			return InventoryRepresentation.unmarshall(Categories.class,
97  					response.getEntity().getContent());
98  		}
99  		return null;
100 	}
101 	
102 	@Override
103 	public Category getCategory(int id) throws Exception {
104 		URI uri = buildURI(CategoriesResource.class,"getCategory")
105 				//marshall @PathParm into the URI
106 				.build(id);
107 		
108 		//build the overall request
109 		HttpGet get = new HttpGet(uri);
110 		get.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML);
111 		
112 		//execute request and look for an OK response with entity
113 		HttpResponse response = client.execute(get);
114 		log.info(String.format("%s %s", get.getURI(), response));
115 		if (Response.Status.OK.getStatusCode() == response.getStatusLine().getStatusCode()) {
116 			return InventoryRepresentation.unmarshall(Category.class,
117 					response.getEntity().getContent());
118 		}
119 		return null;
120 	}
121 	
122 	@Override
123 	public boolean deleteCategory(int id) throws Exception {
124 		URI uri = buildURI(CategoriesResource.class,"deleteCategory")
125 				//marshall @PathParm into the URI
126 				.build(id);
127 		
128 		//build the overall request
129 		HttpDelete delete = new HttpDelete(uri);
130 
131 		//execute request and look for an OK response without an entity
132 		HttpResponse response = client.execute(delete);
133 		log.info(String.format("%s %s", delete.getURI(), response));
134 		if (Response.Status.OK.getStatusCode() == response.getStatusLine().getStatusCode()) {
135 			return true;
136 		}
137 		EntityUtils.consume(response.getEntity()); //must read returned data to release conn
138 		return false;
139 	}
140 	
141 	/**
142 	 * This method uses HTML FORM mechanism to POST a new product in the
143 	 * inventory. 
144 	 */
145 	@Override
146 	public Product createProduct(Product product, String categoryName) 
147 		throws Exception {
148 		URI uri = buildURI(ProductsResource.class,"createProduct")
149 				//no @PathParams here
150 				.build();
151 
152 		//build the form data with the request parameters
153 		List<NameValuePair> params = new ArrayList<NameValuePair>();
154 		params.add(new BasicNameValuePair("name", product.getName()));
155 		params.add(new BasicNameValuePair("category", categoryName));
156 		if (product.getQuantity()!=null) {
157 			params.add(new BasicNameValuePair("quantity", product.getQuantity().toString()));
158 		}
159 		if (product.getPrice() != null) {
160 			params.add(new BasicNameValuePair("price", product.getPrice().toString()));
161 		}
162 
163 		//create the request
164 		HttpPost post = new HttpPost(uri);
165 		post.addHeader(HttpHeaders.CONTENT_ENCODING, MediaType.APPLICATION_FORM_URLENCODED);
166 		post.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML);
167 		post.setEntity(new UrlEncodedFormEntity(params));
168 			
169 		//issue the request and check the response
170 		HttpResponse response = client.execute(post);
171 		log.info(String.format("%s %s", post.getURI(), response));
172 		if (Response.Status.CREATED.getStatusCode() == response.getStatusLine().getStatusCode()) {
173 			return InventoryRepresentation.unmarshall(Product.class,response.getEntity().getContent());
174 		}
175 		return null;
176 	}
177 	
178 	@Override
179 	public Products findProductsByName(String name, int offset, int limit) throws Exception {
180 		URI uri = buildURI(ProductsResource.class,"findProductsByName")
181 				//marshall @QueryParams into URI
182 				.queryParam("name", name)
183 				.queryParam("offset", offset)
184 				.queryParam("limit", limit)
185 				.build();
186 			
187 		//build the overall request
188 		HttpGet get = new HttpGet(uri);
189 		get.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML);
190 		
191 		//issue request and look for OK response with entity
192 		HttpResponse response = client.execute(get);
193 		log.info(String.format("%s %s", get.getURI(), response));
194 		if (Response.Status.OK.getStatusCode() == response.getStatusLine().getStatusCode()) {
195 			return InventoryRepresentation.unmarshall(Products.class,
196 					response.getEntity().getContent());
197 		}
198 		return null;
199 	}
200 	
201 	@Override
202 	public Product getProduct(int id) throws Exception {
203 		URI uri = buildURI(ProductsResource.class,"getProduct")
204 				//marshall @PathParm into the URI
205 				.build(id);
206 			
207 		//build overall request
208 		HttpGet get = new HttpGet(uri);
209 		get.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML);
210 		
211 		//issue request and look for OK response with entity
212 		HttpResponse response = client.execute(get);
213 		log.info(String.format("%s %s", get.getURI(), response));
214 		if (Response.Status.OK.getStatusCode() == response.getStatusLine().getStatusCode()) {
215 			return InventoryRepresentation.unmarshall(Product.class,
216 					response.getEntity().getContent());
217 		}
218 		return null;
219 	}
220 	
221 	@Override
222 	public Product updateProduct(Product product) throws Exception {
223 		URI uri = buildURI(ProductsResource.class,"updateProduct")
224 				//marshall @PathParm into the URI
225 				.build(product.getId());
226 			
227 		//build overall request
228 		HttpPut put = new HttpPut(uri);
229 		put.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML);
230 		put.setEntity(new StringEntity(product.toString(), "UTF-8"));
231 		
232 		//issue request and look for OK with entity
233 		HttpResponse response = client.execute(put);
234 		log.info(String.format("%s %s", put.getURI(), response));
235 		if (Response.Status.OK.getStatusCode() == response.getStatusLine().getStatusCode()) {
236 			return InventoryRepresentation.unmarshall(Product.class,
237 					response.getEntity().getContent());
238 		}
239 		return null;
240 	}
241 
242 	@Override
243 	public boolean deleteProduct(int id) throws Exception {
244 		URI uri = buildURI(ProductsResource.class,"deleteProduct")
245 				//marshall @PathParm into the URI
246 				.build(id);
247 			
248 		//build overall request
249 		HttpDelete delete = new HttpDelete(uri);
250 		
251 		//issue request and look for OK respose without and entity
252 		HttpResponse response = client.execute(delete);
253 		log.info(String.format("%s %s", delete.getURI(), response));
254 		if (Response.Status.OK.getStatusCode() == response.getStatusLine().getStatusCode()) {
255 			return true;
256 		}
257 		EntityUtils.consume(response.getEntity()); //must read returned data to release conn
258 		return false;
259 	}
260 }