cxf-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ryan Zoerner <ryanzoer...@gmail.com>
Subject Basic Http Demo and the refactoring that I did, in the course of figuring out how it worked.
Date Thu, 12 May 2011 06:32:19 GMT
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

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message