I've decided that I am not posting enough about my actual coding to the dev list.
In an effort to set a better backdrop for conversations about my current progress, and level of learning, I've decided to try and fix that. This email is the first of what will be numerous emails, talking, in a little detail about what actual coding I have worked on and to what effect. I also will probably make mention of some of the various pitfalls that I've encountered and what I did to fix the problem. I may also, at some times post some questions about things that I have not been able to figure out, as I think that it might aid the discussion process. That said, here is the first of what I intend to have be numerous emails to the list. JAX_RS/demo At cxf/distribution/src/main/release/samples/jax_rs/basic ( http://svn.apache.org/viewvc/cxf/trunk/distribution/src/main/release/samples/jax_rs/basic/) is a basic http demo. I found the client code to be large and unwieldly, so I refactored it. I also found it hard to understand, at first, but the key, with the GET request is that the client opens a connection with the server, at the URI associated with a given resource. The client opens a printStream that is associated with the connection, and from that connection the client obtains the return information that would normally be associated with a GET request. It may be that since the only @Path in CustomerService with "/customerservice/customers/{id}" is the GET method, that the service automatically just queries that @Path and assumes a GET request, since that method is annotated with the @GET annotation. If you annotated it with more than one HTTP RequestType, I am unsure what would happen at the moment. That said, here is the refactoring part of the code. Client.java ----------------------------------------------------------------------------------------------- /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unewlineess required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package demo.jaxrs.client; import ... public final class Client { private Client() {} /** * This client should run batch processing on file input using the methods * of CustomerService. You shouldn't have to call the methods of any * ComplexEntity. * * @param args * @throws Exception */ public static void main(String args[]) throws Exception { // sends a URL to "/customerservice/customers/123" and prints the returned // xml to the screen. printGETCustomerFromID(123); newline(); // sends a URL to "/customerservice/orders/223/products/323" and prints the returned // xml to the screen. printGETProductFromID(223, 323); printGETProductFromID(224, 324); printGETProductFromID(225, 325); newline(); updatePUTCustomerDataFile(); newline(); addPOSTCustomerDataFile(); newline(); System.exit(0); } private static void printGETCustomerFromID(long customerID) throws MalformedURLException, IOException, Exception { System.out.println("Sent HTTP GET request to query customer info"); URL url = new URL("http://localhost:9000/customerservice/customers/" + customerID); System.out.println(url); // equivalent to url.openConnection().getInputStream(); // it gets an InputStream from the java.net.URLConnection associated with the // supplied URL. InputStream in = url.openStream(); // this is equivalent to calling url.openConnection().getContent() // or, you can use shorthand by calling url.getContent(). The important // thing to note is that a connection has actually been opened; there is // no such thing as url content, that is not associated with you opening // a connection through that url, being stored on the server in the absence // of a url request. This seems silly, but if you call url.getHeader(2);, // it makes one wonder how the url object or the server simply new what // item 2 of the headers would look like without generating all of them, // which it must do; and in the case it generates a full response to the // request, but the methods enable you to treat it as though it is stored // data, when in actuality, it is reprocessed on each method call. // ( .openConnection() ) System.out.println(getStringFromInputStream(in)); newline(); } ... } ----------------------------------------------------------------------------------------------- The only additions are that I have changed the method signatures so as to accept a customer ID as a parameter. I also refactored the GETproduct method in the following way: Client.java ----------------------------------------------------------------------------------------------- ... private static void printGETProductFromID(long orderID, long productID) throws MalformedURLException, Exception { System.out .println("Sent HTTP GET request to query sub resource product info"); URL url = new URL( "http://localhost:9000/customerservice/orders/" + orderID + "/products/" + productID); System.out.println(url); InputStream in = url.openStream(); //if( in.equals(null) ) { System.out.println("inputStream comes back null"); } System.out.println(getStringFromInputStream(in)); newline(); } ... ----------------------------------------------------------------------------------------------- You can see what the added parameters do. This was to remove "magic numbers" from the code, a practice which we were taught to make use of, and it was to enable the easy generation of more customers, without having to type so much. In order to make this code work, I had to refactor the ...server.CustomerService.java and ...server.Order.java files in the following way (please note the comments on the init methods.): CustomerService.java ----------------------------------------------------------------------------------------------- package demo.jaxrs.server; ... @Path("/customerservice/") public class CustomerService { long currentId = 123; Map<Long,Customer> customersByID = new HashMap<Long,Customer>(); Map<String,Customer> customersByName = new HashMap<String,Customer>(); Map<Long,Order> orders = new HashMap<Long,Order>(); public CustomerService() { init(); } ... // The init method is called by the Constructor and instantiates the customers // and product-orders in the system, when the Client is started. final void init() { initCustomer(123, "John"); initOrder(223, 323); initOrder(224, 324); initOrder(225, 325); } // when a new Order is constructed, the init() method of Order is called, // which in turn, instantiates a Product. Therefore, both the orderID and // productID's are sent to this method. private void initOrder(long orderID, long productID) { Order o = new Order(orderID, productID); o.setDescription("order " + orderID); o.setId(orderID); orders.put(o.getId(), o); } private void initCustomer(long customerID, String customerName) { Customer c = new Customer(); c.setName(customerName); c.setId(customerID); customersByID.put(c.getId(), c); customersByName.put(c.getName(), c); } } ----------------------------------------------------------------------------------------------- Order.java ----------------------------------------------------------------------------------------------- package demo.jaxrs.server; ... @XmlRootElement(name = "Order") public class Order { public Order() { init(); } // This method enables the creation of multiple products each with an individual // productID, whereas, before, the productID was hand coded into the init method // below. public Order(long orderID, long productID) { init(productID); } @GET @Path("products/{productId}/") public Product getProduct(@PathParam("productId") int productId) { System.out.println("----invoking getProduct with id: " + productId); Product p = products.get(new Long(productId)); return p; } final void init() { Product p = new Product(); p.setId(323); p.setDescription("product 323"); products.put(p.getId(), p); } // this is the method enables the addition of more than one product, through the use of // parameters, rather than through hard-coding them into init. final void init(long productID) { Product p = new Product(); long pID = productID; p.setId(pID); p.setDescription("product " + pID); System.out.println(p.getDescription()); products.put(p.getId(), p); } ----------------------------------------------------------------------------------------------- So, initially, these are the improvements that I made to the 'basic' http demo, when I first downloaded it and went over it. As far as the @XmlRootElement annotations go, the Server returns an xml element, when queried, but the only times that the element is touched are when it is instantiated, through the use of its corresponding class, and when it is accessed, in the first case, via the GET method of the CustomerService class, upon receiving a URL from the client, locating that class, through means of the @Path annotation. Here is the code from the CustomerService class, that I will discuss: ----------------------------------------------------------------------------------------------- ... @Path("/customerservice/") public class CustomerService { ... @GET @Path("/customers/{id}/") public Customer getCustomer(@PathParam("id") String id) { System.out.println("----invoking getCustomer, Customer id is: " + id); long idNumber = Long.parseLong(id); Customer c = customers.get(idNumber); return c; } ... ----------------------------------------------------------------------------------------------- As you saw, Customer is annotated with the @XmlRootElement annotation. In the Java EE api documentation, it states: "When a top level class or an enum type is annotated with the @XmlRootElement annotation, then its value is represented as XML element in an XML document." I'm not sure what mechanism java EE uses to ensure this, but I think that this annotation is the reason why that when the CustomerService object returns a Customer object, that the Service returns the Object in XML format, through the open URL connection. That is all for now. I intend to make small steps towards building upon this in the future. I hope that this will set a good backdrop for discussion and me to ask questions, if necessary. Ryan
