Gorgeous Skin Banish Blush















A Diet for Gorgeous Skin iVillage Beauty & Style Health & Well-being Diet & Fitness Love & Sex Pregnancy & Parenting Home & Food Entertainment Magazines you are here iVillage Cosmopolitan Beauty & Style Beauty Features Cosmopolitan iVillage the Web Subscribe • In This Issue • Past Issue Archive • Free Newsletter • Get Cosmo Headlines Daily • Gift Subscriptions • Customer Service • Write to Us • Cosmo FAQs Experts • Carnal Counselor • Ask Him Anything Sex & Love • Sex Articles • Bedroom Blog • Sex Position of the Week • Sex Tips from Guys • Bedside Astrologer • Daily Horoscopes • Sexual Health • Passion Polls • Sexy Postcards • Kama Sutra Match & Moan Game Beauty & Style • Cosmo's Winter Look • Beauty Q&A • Beauty Features • Cosmo Fashion • Style Secrets Connect with Cosmo • Cosmo Wants to Know • Free Stuff from Cosmo • Cosmo Quiz • Cosmo Exclusives • For Guys Only • Message Boards • Red-Hot Reads • Confess to Cosmo • Make Cosmo Your Homepage Men • Guy Candy Gallery • Man Match Game • The Man Menu • His Moan Zones • Sex Up Your Screen iVILLAGE TOPICS • Cheating • Hair • Bedroom Concerns • Safe Sex • Taboos • What Guys Want • Makeovers PAGE 3 of: A Diet for Gorgeous Skin Banish Blush Triggers While a little bit of color in your cheeks is flattering, full-on ruddiness isn't exactly the look you're after. And certain foods and beverages, such as spices, cured meats, MSG and alcohol (particularly red wine), cause blood vessels to dilate, bringing on facial redness, says John Wolf, M.D., chairman of the department of dermatology at Baylor College of Medicine in Houston. Simple food switch: If you tend to redden easily, pay attention to which foods bring it on, since people have different triggers. If spicy foods get you, order Thai without the curry and steer clear of wasabi when you go for sushi. If you flush after a few drinks, cut back on the booze or at least pass on red wine. PAGE 3 OF 4 NEXT: Indulge in Olive Oil in this article PAGE 1: Lay Off the White Stuff PAGE 2: Savor Seafood PAGE 3: Banish Blush Triggers PAGE 4: Indulge in Olive Oil printer friendly version Subscribe to Cosmopolitan related links SUBSCRIBE: Get more of what you want from Cosmo! Click for details ARTICLE: Find the Best Brush for You ARTICLE: How to Blow-Dry the Back of Your Hair ARTICLE: What Your Look Says About You ARTICLE: 7 Hot-Weather Beauty Horrors (and How to Avoid Them) ARTICLE: Your 10 Most Bewildering Beauty Questions -- Answered! USA: 12 issues for $18 • Non-USA: click here Name Address 1 Address 2 City State Zip Email Yes, I Would like to receive special offers and discounts by email from Cosmopolitan ( privacy policy ) Send this page to a friend Friend's Email: Home | Subscribe | Experts | Sex & Love | Beauty & Style Connect with Cosmo | Men Name Address City State Postal Code Email We'll bill you later -- 12 issues for just $18. Non-USA Gift Subscriptions Subscriptions Service Write to us Get Cosmo Headlines Daily! On iVillage: Home Topics A-Z Message Boards Quizzes Newsletters Free Stuff Astrology Multimedia Blogs Beauty & Style Health & Well-Being Diet & Fitness Love & Sex Pregnancy & Parenting Home & Food Entertainment Special Sections: Personals Meet Marcia Cross Snack Swapper Car Safety Shopping Coupons Games Magazines: Cosmopolitan Country Living Good Housekeeping House Beautiful Marie Claire Redbook Town & Country Terms of Service Privacy Policy About iVillage Customer Support ©1995-2006 iVillage. All Rights Reserved.



SOAP In this chapter:

Java & XML, 2nd Edition: Chapter 12: SOAP Java & XML, 2nd Edition Solutions to Real-World Problems By Brett McLaughlin 2nd Edition September 2001 0-596-00197-5, Order Number: 1975 528 pages, $44.95 Chapter 12 SOAP In this chapter: Starting Out Setting Up Getting Dirty Going Further What's Next? SOAP is the Simple Object Access Protocol. If you haven't heard of it by now, you've probably been living under a rock somewhere. It's become the newest craze in web programming, and is integral to the web services fanaticism that has taken hold of the latest generation of web development. If you've heard of .NET from Microsoft or the peer-to-peer "revolution," then you've heard about technologies that rely on SOAP (even if you don't know it). There's not one but two SOAP implementations going on over at Apache, and Microsoft has hundreds of pages on their MSDN web site devoted to it ( http://msdn.microsoft.com ). In this chapter, I explain what SOAP is, and why it is such an important part of where the web development paradigm is moving. That will help you get the fundamentals down, and prepare you for actually working with a SOAP toolkit. From there, I briefly run over the SOAP projects currently available, and then delve into the Apache implementation. This chapter is not meant to be the complete picture on SOAP; the next chapter fills in lots of gaps. Take this as the first part of a miniseries; many of your questions at the end of this chapter will be answered in the next. Starting Out The first thing to do is get an understanding of what SOAP is. You can read through the complete W3C note submission, which is fairly lengthy, at http://www.w3.org/TR/SOAP . When you take away all of the hype, SOAP is just a protocol. It's a simple protocol (to use, not necessarily to write), based on the idea that at some point in a distributed architecture, you'll need to exchange information. Additionally, in a system that is probably overtaxed and process-heavy, this protocol is lightweight, requiring a minimal amount of overhead. Finally, it allows all this to occur over HTTP, which allows you to get around tricky issues like firewalls and keep away from having all sorts of sockets listening on oddly numbered ports. Once you get that down, everything else is just details. Of course, I'm sure you're here for the details, so I won't leave them out. There are three basic components to the SOAP specification: the SOAP envelope, a set of encoding rules, and a means of interaction between request and response. Begin to think about a SOAP message as an actual letter; you know, those antiquated things in envelopes with postage and an address scrawled across the front? That analogy helps SOAP concepts like "envelope" make a lot more sense. Figure 12-1 seeks to illustrate the SOAP process in terms of this analog. Figure 12-1. The SOAP message process With this picture in your head, let's look at the three components of the SOAP specification. I cover each briefly and provide examples that illustrate these concepts more completely. Additionally, it's these three key components that make SOAP so important and valuable. Error handling, support for a variety of encodings, serialization of custom parameters, and the fact that SOAP runs over HTTP make it more attractive in many cases than the other choices for a distributed protocol. [1] Additionally, SOAP provides a high degree of interoperability with other applications, which I delve into more completely in the next chapter. For now, I want to focus on the basic pieces of SOAP. The Envelope The SOAP envelope is analogous to the envelope of an actual letter. It supplies information about the message that is being encoded in a SOAP payload, including data relating to the recipient and sender, as well as details about the message itself. For example, the header of the SOAP envelope can specify exactly how a message must be processed. Before an application goes forward with processing a message, the application can determine information about a message, including whether it will even be able to process the message. Distinct from the situation with standard XML-RPC calls (remember that? XML-RPC messages, encoding, and the rest are all wrapped into a single XML fragment), with SOAP actual interpretation occurs in order to determine something about the message. A typical SOAP message can also include the encoding style, which assists the recipient in interpreting the message. Example 12-1 shows the SOAP envelope, complete with the specified encoding. Example 12-1: The SOAP envelope <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" soap:encodingStyle="http://myHost.com/encodings/secureEncoding" > <soap:Body> <article xmlns="http://www.ibm.com/developer"> <name>Soapbox</name> <url> http://www-106.ibm.com/developerworks/library/x-soapbx1.html </url> </article> </soap:Body> </soap:Envelope> You can see that an encoding is specified within the envelope, allowing an application to determine (using the value of the encodingStyle attribute) whether it can read the incoming message situated within the Body element. Be sure to get the SOAP envelope namespace correct, or SOAP servers that receive your message will trigger version mismatch errors, and you won't be able to interoperate with them. Encoding The second major element that SOAP brings to the table is a simple means of encoding user-defined datatypes. In RPC (and XML-RPC), encoding can only occur for a predefined set of datatypes: those that are supported by whatever XML-RPC toolkit you download. Encoding other types requires modifying the actual RPC server and clients themselves. With SOAP, however, XML schemas can be used to easily specify new datatypes (using the complexType structure discussed way back in Chapter 2), and those new types can be easily represented in XML as part of a SOAP payload. Because of this integration with XML Schema, you can encode any datatype in a SOAP message that you can logically describe in an XML schema. Invocation The best way to understand how SOAP invocation works is to compare it with something you already know, such as XML-RPC. If you recall, an XML-RPC call would look something like the code fragment shown in Example 12-2 . Example 12-2: Invocation in XML-RPC // Specify the XML parser to use XmlRpc.setDriver("org.apache.xerces.parsers.SAXParser"); // Specify the server to connect to XmlRpcClient client = new XmlRpcClient("http://rpc.middleearth.com"); // Create the parameters Vector params = new Vector( ); params.addElement(flightNumber); params.addElement(numSeats); params.addElement(creditCardType); params.addElement(creditCardNum); // Request reservation Boolean boughtTickets = (Boolean)client.execute("ticketCounter.buyTickets", params); // Deal with the response I've coded up a simple ticket counter-style application. Now, look at Example 12-3 , which shows the same call in SOAP. Example 12-3: Invocation in SOAP // Create the parameters Vector params = new Vector( ); params.addElement( new Parameter("flightNumber", Integer.class, flightNumber, null)); params.addElement( new Parameter("numSeats", Integer.class, numSeats, null)); params.addElement( new Parameter("creditCardType", String.class, creditCardType, null)); params.addElement( new Parameter("creditCardNumber", Long.class, creditCardNum, null)); // Create the Call object Call call = new Call( ); call.setTargetObjectURI("urn:xmltoday-airline-tickets"); call.setMethodName("buyTickets"); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); call.setParams(params); // Invoke Response res = call.invoke(new URL("http://rpc.middleearth.com"), ""); // Deal with the response As you can see, the actual invocation itself, represented by the Call object, is resident in memory. It allows you to set the target of the call, the method to invoke, the encoding style, the parameters, and more not shown here. It is more flexible than the XML-RPC methodology, allowing you to explicitly set the various parameters that are determined implicitly in XML-RPC. You'll see quite a bit more about this invocation process in the rest of the chapter, including how SOAP provides fault responses, an error hierarchy, and of course the returned results from the call. With that brief introduction, you probably know enough to want to get on with the fun stuff. Let me show you the SOAP implementation I'm going to use, explain why I made that choice, and get to some code. Setting Up Now that you have some basic concepts down, it's time to get going on the fun part, the code. You need a project or product for use, which turns out to be simpler to find than you might think. If you want a Java-based project providing SOAP capability, you don't have to look that far. There are two groups of products out there: commercial and free. As in most of the rest of the book, I'm steering away from covering commercial products. This isn't because they are bad (on the contrary, some are wonderful); it's because I want every reader of this book to be able to use every example. That calls for accessibility, something commercial products don't provide; you have to pay to use them, or download them and at some point the trial period runs out. That brings us to open source projects. In that realm, I see only one available: Apache SOAP. Located online at http://xml.apache.org/soap , this project seeks to provide a SOAP toolkit in Java. Currently in a Version 2.2 release, you can download it from the Apache web site. That's the version and project I use for the examples throughout this chapter. Other Options Before moving on to the installation and setup of Apache SOAP, I will answer a few questions that might be rattling around in your head. It's probably clear why I'm not using a commercial product. However, you may be thinking of a couple of other open source or related options that you might want to use, and wondering why I am not covering those. What about IBM SOAP4J? First on the list of options is IBM's SOAP implementation, IBM SOAP4J. IBM's work is actually the basis of the current Apache SOAP project, much as IBM XML4J fed into what is now the Apache Xerces XML parser project. Expect the IBM implementation to resurface, wrapping the Apache SOAP project's implementation. This is similar to what is happening with IBM's XML4J; it currently just provides IBM packaging over Xerces. This makes some additional levels of vendor-backing available to the open source version, although the two (Apache and IBM) projects are using the same codebase. Isn't Microsoft a player? Yes. Without a doubt, Microsoft and its SOAP implementation, as well as the whole .NET initiative (covered more in the next chapter), are very important. In fact, I wanted to spend some time covering Microsoft's SOAP implementation in detail, but it only supports COM objects and the like, without Java support. For this reason, coverage of it doesn't belong in a book on Java and XML. However, Microsoft (despite the connotations we developers tend to have about the company) is doing important work in web services, and you'd be making a mistake in writing it off, at least in this particular regard. If you need to communicate with COM or Visual Basic components, I highly recommend checking out the Microsoft SOAP toolkit, found online at http://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28000523 along with a lot of other SOAP resources. What's Axis? Those of you who monitor activity in Apache may have heard of Apache Axis. Axis is the next-generation SOAP toolkit, also being developed under the Apache XML umbrella. With SOAP (the specification, not a specific implementation) undergoing fairly fast and radical change these days, tracking it is difficult. Trying to build a version of SOAP that meets current requirements and moves with new development is also awfully tough. As a result, the current Apache SOAP offering is somewhat limited in its construction. Rather than try to rearchitect an existing toolkit, the Apache folks started fresh with a new codebase and project; thus, Axis was born. Additionally, the naming of SOAP was apparently going to change, from SOAP to XP and then to XMLP. As a result, the name of this new SOAP project was uncoupled from the specification name; thus, you have "Axis." Of course, now it looks like the W3C is going back to calling the specification SOAP (Version 1.2, or Version 2.0), so things are even more confusing! Think of IBM SOAP4J as architecture 1 of the SOAP toolkit. Following that is Apache SOAP (covered in this chapter), which is architecture 2. Finally, Axis provides a next-generation architecture, architecture 3. This project is driven by SAX, while Apache SOAP is based upon DOM. Additionally, Axis provides a more user-friendly approach in header interaction, something missing in Apache SOAP. With all of these improvements, you're probably wondering why I'm not covering Axis. It's simply too early. Axis is presently trying to get together a 0.51 release. It's not a beta, or even an alpha, really; it's very early on. While I'd love to cover all the new Axis features, there's no way your boss is going to let you put in a pre-alpha release of open source software in your mission-critical systems, now is there? As a result, I've chosen to focus on something you can use, today : Apache SOAP. I'm sure when Axis does finalize, I'll update this chapter in a subsequent revision of the book. Until then, let's focus on a solution you can use. Installation There are two forms of installation with regard to SOAP. The first is running a SOAP client, using the SOAP API to communicate with a server that can receive SOAP messages. The second is running a SOAP server, which can receive messages from a SOAP client. I cover installation of both cases in this section. The client To use SOAP on a client, you first need to download Apache SOAP, available online at http://xml.apache.org/dist/soap . I've downloaded Version 2.2, in the binary format (in the version-2.2 subdirectory). You should then extract the contents of the archive into a directory on your machine; my installation is in the javaxml2 directory ( c:\javaxml2 on my Windows machine, /javaxml2 on my Mac OS X machine). The result is /javaxml2/soap-2_2 . You'll also need to download the JavaMail package, available from Sun at http://java.sun.com/products/javamail/ . This is for the SMTP transfer protocol support included in Apache SOAP. Then, download the JavaBeans Activation Framework (JAF), also from Sun, available online at http://java.sun.com/products/beans/glasgow/jaf.html . I'm assuming that you still have Xerces or another XML parser available for use. NOTE: Ensure your XML parser is JAXP-compatible and namespace-aware. Your parser, unless it's a very special case, probably meets both of these requirements. If you have problems, go back to using Xerces. NOTE: Use a recent version of Xerces; Version 1.4 or greater should suffice. There are a number of issues with SOAP and Xerces 1.3(.1), so I'd avoid that combination like the plague. Expand both the JavaMail and JAF packages, and then add the included jar files to your classpath, as well as the soap.jar library. Each of these jar files is either in the root directory or in the lib/ directory of the relevant installation. At the end, your classpath should look something like this: $ echo $CLASSPATH /javaxml2/soap-2_2/lib/soap.jar:/javaxml2/lib/xerces.jar: /javaxml2/javamail-1.2/mail.jar:/javaxml2/jaf-1.0.1/activation.jar On Windows, it should look like: c:\>echo %CLASSPATH% c:\javaxml2\soap-2_2\lib\soap.jar;c:\javaxml2\lib\xerces.jar; c:\javaxml2\javamail-1.2\mail.jar;c:\javaxml2\jaf-1.0.1\activation.jar Finally, add the javaxml2/soap-2_2/ directory to your classpath if you want to run the SOAP examples. I cover setup for specific examples in this chapter as I get to them. The server To build a SOAP-capable set of server components, you first need a servlet engine. As in earlier chapters, I'll use Apache Tomcat (available from http://jakarta.apache.org ) throughout this chapter for examples. You'll then need to add everything needed on the client to the server's classpath. The easiest way to do that is to drop soap.jar , activation.jar , and mail.jar , as well as your parser, in your servlet engine's library directory. On Tomcat, this is simply the lib/ directory, which contains libraries that should be autoloaded. If you want to support scripting (which is not covered in this chapter, but is in the Apache SOAP examples), you'll need to put bsf.jar (available online at http://oss.software.ibm.com/developerworks/projects/bsf ) and js.jar (available from http://www.mozilla.org/rhino/ ) in the same directory. NOTE: If you are using Xerces with Tomcat, you'll need to perform the same renaming trick I talked about in Chapter 10. Rename parser.jar to z_parser.jar and jaxp.jar to z_jaxp.jar , to ensure that xerces.jar and the included version of JAXP are loaded prior to any other parser or JAXP implementation. Now restart your servlet engine, and you're ready to write SOAP server components. The router servlet and admin client In addition to basic operation, Apache SOAP includes a router servlet as well as an admin client; even if you don't want to use these, I recommend you install them so you can test your SOAP installation. This process is servlet-engine-specific, so I just cover the Tomcat installation here. However, installation instructions for several other servlet engines are available online at http://xml.apache.org/soap/docs/index.html . Installation under Tomcat is simple; just take the soap.war file in the soap-2_2/webapps directory, and drop it in your $TOMCAT_HOME/ webapps directory. That's it! To test the installation, point your web browser to http://localhost:8080/soap/servlet/rpcrouter . You should get a response like that shown in Figure 12-2 . Figure 12-2. The RPC router servlet Although this looks like an error, it does indicate that things are working correctly. You should get the same response pointing your browser to the admin client, at http://localhost:8080/soap/servlet/messagerouter . As a final test of both the server and client, ensure you have followed all the setup instructions so far. Then execute the following Java class as shown, supplying your servlet URL for the RPC router servlet: C:\>java org.apache.soap.server.ServiceManagerClient http://localhost:8080/soap/servlet/rpcrouter list Deployed Services: You should get the empty list of services, as shown here. If you get any other message, consult the long list of possible errors at http://xml.apache.org/soap/docs/trouble/index.html . A fairly complete list of problems that you can run into is there. If you do get the empty list of services, then you're set up and ready to continue with the examples in the rest of this chapter. Getting Dirty There are three basic steps in writing any SOAP-based system, and I'll look at each in turn: Decide on SOAP-RPC or SOAP messaging Write or obtain access to a SOAP service Write or obtain access to a SOAP client The first step is to decide if you want to use SOAP for RPC-style calls, in which a remote procedure is invoked on a server, or for messaging, in which a client simply sends pieces of information to a server. I'll detail these processes in the next section. Once you've made that design decision, you need to access, or code up, a service. Of course, since we're all Java pros here, this chapter shows you how to code up your own. Finally, you need to write the client for this service, and watch things take off. RPC or Messaging? Your first task is actually not code-related but design-related. You need to determine if you want an RPC service or a messaging one. The first, RPC, is something you should be pretty familiar with after the last chapter. A client invokes a remote procedure on a server somewhere, and then gets some sort of response. In this scenario, SOAP is simply acting as a more extensible XML-RPC system, allowing better error handling and passing of complex types across the network. This is a concept you should already understand, and because it turns out that RPC systems are simple to write in SOAP, I'll start off there. This chapter describes how to write an RPC service, and then an RPC client, and put the system in action. The second style of SOAP processing is message-based. Instead of invoking remote procedures, it provides for transfer of information. As you can imagine, this is pretty powerful, and doesn't depend on a client knowing about a particular method on some server. It also models distributed systems more closely, allowing packets of data (packet in the figurative sense, not in the network sense) to be passed around, keeping various systems aware of what other systems are doing. It is also more complicated than the simpler RPC-style programming, so I'll cover it in the next chapter with other business-to-business details after you're well grounded in SOAP-RPC programming. Like most design issues, the actual process of making this decision is left up to you. Look at your application and determine exactly what you want SOAP to do for you. If you have a server and a set of clients that just need to perform tasks remotely, then RPC is probably well suited for your needs. However, in larger systems that are exchanging data rather than performing specific business functions on request, SOAP's messaging capabilities may be a better match. An RPC Service With the formalities out of the way, it's time to get going, fast and furious. As you'll recall from the last chapter, in RPC you need a class that is going to have its methods invoked remotely. Code artifacts I'll start by showing you some code artifacts to have available on the server. These artifacts are classes with methods that are exposed to RPC clients. [2] Rather than use the simple class from last chapter, I offer a slightly more complex example to show you what SOAP can do. In that vein, Example 12-4 is a class that stores a CD inventory, such as an application for an online music store might use. I'm introducing a basic version here, and will add to it later in the chapter. Example 12-4: The CDCatalog class package javaxml2; import java.util.Hashtable; public class CDCatalog { /** The CDs, by title */ private Hashtable catalog; public CDCatalog( ) { catalog = new Hashtable( ); // Seed the catalog catalog.put("Nickel Creek", "Nickel Creek"); catalog.put("Let it Fall", "Sean Watkins"); catalog.put("Aerial Boundaries", "Michael Hedges"); catalog.put("Taproot", "Michael Hedges"); } public void addCD(String title, String artist) { if ((title == null) || (artist == null)) { throw new IllegalArgumentException("Title and artist cannot be null."); } catalog.put(title, artist); } public String getArtist(String title) { if (title == null) { throw new IllegalArgumentException("Title cannot be null."); } // Return the requested CD return (String)catalog.get(title); } public Hashtable list( ) { return catalog; } } This allows for adding a new CD, searching for an artist by a CD title, and getting all current CDs. Take note that the list( ) method returns a Hashtable , and there is nothing special I have to do to make that work; Apache SOAP provides automatic mapping of the Hashtable Java type, much as XML-RPC did. Compile this class, and make sure you've got everything typed in (or downloaded, if you choose) correctly. Notice that the CDCatalog class has no knowledge about SOAP. This means you can take your existing Java classes and expose them through SOAP-RPC, which reduces the work required on your end to move to a SOAP-based architecture if needed. Deployment descriptors With the Java coding done, you now need to define a deployment descriptor. This specifies several key things to a SOAP server: The URN of the SOAP service for clients to access The method or methods available to clients The serialization and deserialization handlers for any custom classes The first is similar to a URL, and required for a client to connect to any SOAP server. The second is exactly what you expect: a list of methods letting the client know what are allowable artifacts for a SOAP client. It also lets the SOAP server, which I'll cover in a moment, know what requests to accept. The third is a means of telling the SOAP server how to handle any custom parameters; I'll come back to this in the next section when I add some more complex behavior to the catalog. I'll show you the deployment descriptor and detail each item within it. Example 12-5 is the deployment descriptor for the CDCatalog service we're creating. Example 12-5: The CDCatalog deployment descriptor <isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment" id="urn:cd-catalog" > <isd:provider type="java" scope="Application" methods="addCD getArtist list" > <isd:java class="javaxml2.CDCatalog" static="false" /> </isd:provider> <isd:faultListener>org.apache.soap.server.DOMFaultListener</isd:faultListener> </isd:service> First, I referenced the Apache SOAP deployment namespace, and then supplied a URN for my service through the id attribute. This should be something unique across services, and descriptive of the service. I showed about as much originality in naming the service as Dave Matthews did with his band, but it gets the job done. Then, I specified through the java element the class to expose, including its package name (through the class attribute), and indicated that the methods being exposed were not static ones (through the static attribute). Next, I specified a fault listener implementation to use. Apache's SOAP implementation provides two; I used the first, DOMFaultListener . This listener returns any exception and fault information through an additional DOM element in the response to the client. I'll get back to this when I look at writing clients, so don't worry too much about it right now. The other fault listener implementation is org.apache.soap.server.ExceptionFaultListener . This listener exposes any faults through an additional parameter returned to the client. Since quite a few SOAP-based applications are already going to be working in Java and XML APIs like DOM, it's common to use the DOMFaultListener in most cases. Deploying the service At this point, you've got a working deployment descriptor and a set of code artifacts to expose, and you can deploy your service. Apache SOAP comes with a utility to do this task, provided you have done the setup work. First, you need a deployment descriptor for your service, which I just talked about. Second, you need to make the classes for your service available to the SOAP server. The best way to do this is to jar up the service class from the last section: jar cvf javaxml2.jar javaxml2/CDCatalog.class Take this jar file and drop it into your lib/ directory (or wherever libraries are auto-loaded for your servlet engine), and restart your servlet engine. WARNING: When you do this, you have created a snapshot of your class file. Changing the code in the CDCatalog.java file and recompiling it will not cause the servlet engine to pick up the changes. You'll need to re- jar the archive and copy it over to your lib/ directory each time code changes are made to ensure your service is updated. You'll also want to restart your servlet engine to make sure the changes are picked up by the engine as well. With your service class (or classes) accessible by your SOAP server, you can now deploy the service, using Apache SOAP's org.apache.soap.server.ServiceManager utility class: C:\javaxml2\Ch12>java org.apache.soap.server.ServiceManagerClient http://localhost:8080/soap/servlet/rpcrouter deploy xml\CDCatalogDD.xml The first argument is the SOAP server and RPC router servlet, the second is the action to take, and the third is the relevant deployment descriptor. Once this has executed, verify your service was added: (gandalf)/javaxml2/Ch12$ java org.apache.soap.server.ServiceManagerClient http://localhost:8080/soap/servlet/rpcrouter list Deployed Services: urn:cd-catalog urn:AddressFetcher urn:xml-soap-demo-calculator At a minimum, this should show any and all services you have available on the server. Finally, you can easily undeploy the service, as long as you know its name: C:\javaxml2\Ch12>java org.apache.soap.server.ServiceManagerClient http://localhost:8080/soap/servlet/rpcrouter undeploy urn:cd-catalog Every time you update your service code, you must undeploy and then redeploy to ensure the SOAP server is running the newest copy. An RPC Client Next up is the client. I'm going to keep things simple, and just write a couple of command-line programs that invoke SOAP-RPC. It would be impossible to try and guess your business case, so I just focus on the SOAP details and let you work out integration with your existing software. Once you have the business portion of your code working, there are some basic steps you'll take in every SOAP-RPC call: Create the SOAP-RPC call Set up any type mappings for custom parameters Set the URI of the SOAP service to use Specify the method to invoke Specify the encoding to use Add any parameters to the call Connect to the SOAP service Receive and interpret a response That may seem like a lot, but most of the operations are one- or two-line method invocations. In other words, talking to a SOAP service is generally a piece of cake. Example 12-6 shows the code for the CDAdder class, which allows you to add a new CD to the catalog. Take a look at the code, and then I'll walk you through the juicy bits. Example 12-6: The CDAdder class package javaxml2; import java.net.URL; import java.util.Vector; import org.apache.soap.Constants; import org.apache.soap.Fault; import org.apache.soap.SOAPException; import org.apache.soap.rpc.Call; import org.apache.soap.rpc.Parameter; import org.apache.soap.rpc.Response; public class CDAdder { public void add(URL url, String title, String artist) throws SOAPException { System.out.println("Adding CD titled '" + title + "' by '" + artist + "'"); // Build the Call object Call call = new Call( ); call.setTargetObjectURI("urn:cd-catalog"); call.setMethodName("addCD"); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); // Set up parameters Vector params = new Vector( ); params.addElement(new Parameter("title", String.class, title, null)); params.addElement(new Parameter("artist", String.class, artist, null)); call.setParams(params); // Invoke the call Response response; response = call.invoke(url, ""); if (!response.generatedFault( )) { System.out.println("Successful CD Addition."); } else { Fault fault = response.getFault( ); System.out.println("Error encountered: " + fault.getFaultString( )); } } public static void main(String[] args) { if (args.length != 3) { System.out.println("Usage: java javaxml2.CDAdder [SOAP server URL] " + "\"[CD Title]\" \"[Artist Name]\""); return; } try { // URL for SOAP server to connect to URL url = new URL(args[0]); // Get values for new CD String title = args[1]; String artist = args[2]; // Add the CD CDAdder adder = new CDAdder( ); adder.add(url, title, artist); } catch (Exception e) { e.printStackTrace( ); } } } This program captures the URL of the SOAP server to connect to, as well as information needed to create and add a new CD to the catalog. Then, in the add( ) method, the code creates the SOAP Call object, on which all the interesting interaction occurs. The target URI of the SOAP service and the method to invoke are set on the call, and both match up to values from the service's deployment descriptor from Example 12-5 . Next, the encoding is set, which should always be the constant Constants.NS_URI_SOAP_ENC unless you have very unique encoding needs. The program creates a new Vector populated with SOAP Parameter objects. Each of these represents a parameter to the specified method, and since the addCD( ) method takes two String values, this is pretty simple. Supply the name of the parameter (for use in the XML and debugging), the class for the parameter, and the value. The fourth argument is an optional encoding, if a single parameter needs a special encoding. For no special treatment, the value null suffices. The resulting Vector is then added to the Call object. Once your call is set up, use the invoke( ) method on that object. The return value from this method is an org.apache.soap.Response instance, which is queried for any problems that resulted. This is fairly self-explanatory, so I'll leave it to you to walk through the code. Once you've compiled your client and followed the instructions earlier in this chapter for setting up your classpath, run the example as follows: C:\javaxml2\build>java javaxml2.CDAdder http://localhost:8080/soap/servlet/rpcrouter "Riding the Midnight Train" "Doc Watson" Adding CD titled 'Riding the Midnight Train' by 'Doc Watson' Successful CD Addition Example 12-7 is another simple class, CDLister , which lists all current CDs in the catalog. I won't go into detail on it, as it's very similar to Example 12-6 , and is mainly a reinforcement of what I've already talked about. Example 12-7: The CDLister class package javaxml2; import java.net.URL; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import org.apache.soap.Constants; import org.apache.soap.Fault; import org.apache.soap.SOAPException; import org.apache.soap.rpc.Call; import org.apache.soap.rpc.Parameter; import org.apache.soap.rpc.Response; public class CDLister { public void list(URL url) throws SOAPException { System.out.println("Listing current CD catalog."); // Build the Call object Call call = new Call( ); call.setTargetObjectURI("urn:cd-catalog"); call.setMethodName("list"); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); // No parameters needed // Invoke the call Response response; response = call.invoke(url, ""); if (!response.generatedFault( )) { Parameter returnValue = response.getReturnValue( ); Hashtable catalog = (Hashtable)returnValue.getValue( ); Enumeration e = catalog.keys( ); while (e.hasMoreElements( )) { String title = (String)e.nextElement( ); String artist = (String)catalog.get(title); System.out.println(" '" + title + "' by " + artist); } } else { Fault fault = response.getFault( ); System.out.println("Error encountered: " + fault.getFaultString( )); } } public static void main(String[] args) { if (args.length != 1) { System.out.println("Usage: java javaxml2.CDAdder [SOAP server URL]"); return; } try { // URL for SOAP server to connect to URL url = new URL(args[0]); // List the current CDs CDLister lister = new CDLister( ); lister.list(url); } catch (Exception e) { e.printStackTrace( ); } } } The only difference in this method from the CDAdder class is that the Response object has a return value (the Hashtable from the list( ) method). This is returned as a Parameter object, which allows a client to check its encoding and then extract the actual method return value. Once that's done, the client can use the returned value like any other Java object, and in the example simply runs through the CD catalog and prints out each one. You can now run this additional client to see it in action: C:\javaxml2\build>java javaxml2.CDLister http://localhost:8080/soap/servlet/rpcrouter Listing current CD catalog. 'Riding the Midnight Train' by Doc Watson 'Taproot' by Michael Hedges 'Nickel Creek' by Nickel Creek 'Let it Fall' by Sean Watkins 'Aerial Boundaries' by Michael Hedges That's really all there is to basic RPC functionality in SOAP. I'd like to push on a bit, though, and talk about a few more complex topics. Going Further Although you can now do everything in SOAP you knew how to do in XML-RPC, there is a lot more to SOAP. As I said in the beginning of the chapter, two important things that SOAP brings to the table are the ability to use custom parameters with a minimal amount of effort, and more advanced fault handling. In this section, I cover both of these topics. Custom Parameter Types The most limiting thing with the CD catalog, at least at this point, is that it stores only the title and artist for a given CD. It is much more realistic to have an object (or set of objects) that represents a CD with the title, artist, label, track listings, perhaps a genre, and all sorts of other information. I'm not going to build this entire structure, but will move from a title and artist to a CD object with a title, artist, and label. This object needs to be passed from the client to the server and back, and demonstrates how SOAP can handle these custom types. Example 12-8 shows this new class. Example 12-8: The CD class package javaxml2; public class CD { /** The title of the CD */ private String title; /** The artist performing on the CD */ private String artist; /** The label of the CD */ private String label; public CD( ) { // Default constructor } public CD(String title, String artist, String label) { this.title = title; this.artist = artist; this.label = label; } public String getTitle( ) { return title; } public void setTitle(String title) { this.title = title; } public String getArtist( ) { return artist; } public void setArtist(String artist) { this.artist = artist; } public String getLabel( ) { return label; } public void setLabel(String label) { this.label = label; } public String toString( ) { return "'" + title + "' by " + artist + ", on " + label; } } This requires a whole slew of changes to the CDCatalog class as well. Example 12-9 shows a modified version of this class with the changes that use the new CD support class highlighted. Example 12-9: An updated CDCatalog class package javaxml2; import java.util.Hashtable; public class CDCatalog { /** The CDs, by title */ private Hashtable catalog; public CDCatalog( ) { catalog = new Hashtable( ); // Seed the catalog addCD(new CD("Nickel Creek", "Nickel Creek", "Sugar Hill")); addCD(new CD("Let it Fall", "Sean Watkins", "Sugar Hill")); addCD(new CD("Aerial Boundaries", "Michael Hedges", "Windham Hill")); addCD(new CD("Taproot", "Michael Hedges", "Windham Hill")); } public void addCD(CD cd) { if (cd == null) { throw new IllegalArgumentException("The CD object cannot be null."); } catalog.put(cd.getTitle( ), cd); } public CD getCD(String title) { if (title == null) { throw new IllegalArgumentException("Title cannot be null."); } // Return the requested CD return (CD)catalog.get(title); } public Hashtable list( ) { return catalog; } } In addition to the obvious changes, I've also updated the old getArtist(String title) method to getCD(String title) , and made the return value a CD object. This means the SOAP server will need to serialize and deserialize this new class, and the client will be updated. First, I look at an updated deployment descriptor that details the serialization issues related to this custom type. Add the following lines to the deployment descriptor for the CD catalog, as well as changing the available method names to match the updated CDCatalog class: <isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment" id="urn:cd-catalog" > <isd:provider type="java" scope="Application" methods=" addCD getCD list " > <isd:java class="javaxml2.CDCatalog" static="false" /> </isd:provider> <isd:faultListener>org.apache.soap.server.DOMFaultListener</isd:faultListener> <isd:mappings> <isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:x="urn:cd-catalog-demo" qname="x:cd" javaType="javaxml2.CD" java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer" xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/> </isd:mappings> </isd:service> The new element, mappings , specifies how a SOAP server should handle custom parameters such as the CD class. First, define a map element for each custom parameter type. For the encodingStyle attribute, at least as of Apache SOAP 2.2, you should always supply the value http://schemas.xmlsoap.org/soap/encoding/ , the only encoding currently supported. You need to supply a namespace for the custom type and then the name of the class, with this namespace prefix, for the type. In my case, I used a "dummy" namespace and the simple prefix "x" for this purpose. Then, using the javaType attribute, supply the actual Java class name: javaxml2.CD in this case. Finally, the magic occurs in the java2XMLClassName and xml2JavaClassName attributes. These specify a class to convert from Java to XML and from XML to Java, respectively. I've used the incredibly handy BeanSerializer class, also provided with Apache SOAP. If your custom parameter is in a JavaBean format, this serializer and deserializer will save you from having to write your own. You need to have a class with a default constructor (remember that I defined an empty, no-args constructor within the CD class), and expose all the data in that class through setXXX and getXXX style methods. Since the CD class fits the bill here, the BeanSerializer works perfectly. NOTE: It's no accident that the CD class follows the JavaBean conventions. Most data classes fit easily into this format, and I knew I wanted to avoid writing my own custom serializer and deserializer. These are a pain to write (not overly difficult, but easy to mess up), and I recommend you go to great lengths to try and use the Bean conventions in your own custom parameters. In many cases, the Bean conventions only require that a default constructor (with no arguments) is present in your class. Now recreate your service jar file. Then, redeploy your service: (gandalf)/javaxml2/Ch12$ java org.apache.soap.server.ServiceManagerClient http://localhost:8080/soap/servlet/rpcrouter xml/CDCatalogDD.xml WARNING: If you have kept your servlet engine running and the service deployed all this time, you'll need to restart the servlet engine to activate the new classes for the SOAP service, and redeploy the service. At this point, all that's left is modifying the client to use the new class and methods. Example 12-10 is an updated version of the client class CDAdder . The changes from the previous version of the class are highlighted. Example 12-10: The updated CDAdder class package javaxml2; import java.net.URL; import java.util.Vector; import org.apache.soap.Constants; import org.apache.soap.Fault; import org.apache.soap.SOAPException; import org.apache.soap.encoding.SOAPMappingRegistry; import org.apache.soap.encoding.soapenc.BeanSerializer; import org.apache.soap.rpc.Call; import org.apache.soap.rpc.Parameter; import org.apache.soap.rpc.Response; import org.apache.soap.util.xml.QName; public class CDAdder { public void add(URL url, String title, String artist, String label ) throws SOAPException { System.out.println("Adding CD titled '" + title + "' by '" + artist + "' , on the label " + label ); CD cd = new CD(title, artist, label); // Map this type so SOAP can use it SOAPMappingRegistry registry = new SOAPMappingRegistry( ); BeanSerializer serializer = new BeanSerializer( ); registry.mapTypes(Constants.NS_URI_SOAP_ENC, new QName("urn:cd-catalog-demo", "cd"), CD.class, serializer, serializer); // Build the Call object Call call = new Call( ); call.setSOAPMappingRegistry(registry); call.setTargetObjectURI("urn:cd-catalog"); call.setMethodName("addCD"); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); // Set up parameters Vector params = new Vector( ); params.addElement(new Parameter("cd", CD.class, cd, null)); call.setParams(params); // Invoke the call Response response; response = call.invoke(url, ""); if (!response.generatedFault( )) { System.out.println("Successful CD Addition."); } else { Fault fault = response.getFault( ); System.out.println("Error encountered: " + fault.getFaultString( )); } } public static void main(String[] args) { if (args.length != 4) { System.out.println("Usage: java javaxml2.CDAdder [SOAP server URL] " + "\"[CD Title]\" \"[Artist Name]\" \"[CD Label]\""); return; } try { // URL for SOAP server to connect to URL url = new URL(args[0]); // Get values for new CD String title = args[1]; String artist = args[2]; String label = args[3]; // Add the CD CDAdder adder = new CDAdder( ); adder.add(url, title, artist, label ); } catch (Exception e) { e.printStackTrace( ); } } } The only really interesting change is in dealing with the mapping of the CD class: // Map this type so SOAP can use it SOAPMappingRegistry registry = new SOAPMappingRegistry( ); BeanSerializer serializer = new BeanSerializer( ); registry.mapTypes(Constants.NS_URI_SOAP_ENC, new QName("urn:cd-catalog-demo", "cd"), CD.class, serializer, serializer); This is how a custom parameter can be encoded and sent across the wire. I already discussed how the BeanSerializer class could be used to handle parameters in the JavaBean format, such as the CD class. To specify that to the server, I used the deployment descriptor; however, now I need to let the client know to use this serializer and deserializer. This is what the SOAPMappingRegistry class allows. The mapTypes( ) method takes in an encoding string (again, using the constant NS_URI_SOAP_ENC is the best idea here), and information about the parameter type a special serialization should be used for. First, a QName is supplied. This is why the odd namespacing was used back in the deployment descriptor; you need to specify the same URN here, as well as the local name of the element (in this case "CD"), then the Java Class object of the class to be serialized ( CD.class ), and finally the class instance for serialization and deserialization. In the case of the BeanSerializer , the same instance works for both. Once all this is set up in the registry, let the Call object know about it through the setSOAPMapping-Registry( ) method. You can run this class just as before, adding the CD label, and things should work smoothly: C:\javaxml2\build>java javaxml2.CDAdder http://localhost:8080/soap/servlet/rpcrouter "Tony Rice" "Manzanita" "Sugar Hill" Adding CD titled 'Tony Rice' by 'Manzanita', on the label Sugar Hill Successful CD Addition. I'll leave it up to you to modify the CDLister class in the same fashion, and the downloadable samples have this updated class as well. NOTE: You might think that since the CDLister class doesn't deal directly with a CD object (the return value of the list( ) method was a Hashtable ), you don't need to make any changes. However, the returned Hashtable contains instances of CD objects. If SOAP doesn't know how to deserialize these, your client is going to give you an error. Therefore, you must specify a SOAPMappingRegistry instance on the Call object to make things work. Better Error Handling Now that you're tossing around custom objects, making RPC calls, and generally showing up everyone else in the office, let me talk about a less exciting topic: error handling. In any network transaction, many things can go wrong. The service isn't running, an error occurs on the server, objects can't be found, classes are missing, and a whole lot of other problems can arise. Until now, I just used the fault.getString( ) method to report errors. But this method isn't always very helpful. To see it in action, comment out the following line in the CDCatalog constructor: public CDCatalog( ) { //catalog = new Hashtable( ); // Seed the catalog addCD(new CD("Nickel Creek", "Nickel Creek", "Sugar Hill")); addCD(new CD("Let it Fall", "Sean Watkins", "Sugar Hill")); addCD(new CD("Aerial Boundaries", "Michael Hedges", "Windham Hill")); addCD(new CD("Taproot", "Michael Hedges", "Windham Hill")); } Recompile, restart your server engine, and redeploy. The result is that a NullPointerException occurs when the class constructor tries to add a CD to an uninitialized Hashtable . Running the client will let you know an error has occurred, but not in a very meaningful way: (gandalf)/javaxml2/build$ java javaxml2.CDLister http://localhost:8080/soap/servlet/rpcrouter Listing current CD catalog. Error encountered: Unable to resolve target object: null This isn't exactly the type of information you need to track down the problem. However, the framework is in place to do a better job of error handling; remember the DOMFaultListener you specified as the value of the faultListener element? This is where it comes into play. The returned Fault object in the case of a problem (as in this one) contains a DOM org.w3c.dom.Element with detailed error information. First, add an import statement for java.util.Iterator to your client source code: import java.net.URL; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.Vector; import org.apache.soap.Constants; import org.apache.soap.Fault; import org.apache.soap.SOAPException; import org.apache.soap.encoding.SOAPMappingRegistry; import org.apache.soap.encoding.soapenc.BeanSerializer; import org.apache.soap.rpc.Call; import org.apache.soap.rpc.Parameter; import org.apache.soap.rpc.Response; import org.apache.soap.util.xml.QName; Next, make the following change to how errors are handled in the list( ) method: if (!response.generatedFault( )) { Parameter returnValue = response.getReturnValue( ); Hashtable catalog = (Hashtable)returnValue.getValue( ); Enumeration e = catalog.keys( ); while (e.hasMoreElements( )) { String title = (String)e.nextElement( ); CD cd = (CD)catalog.get(title); System.out.println(" '" + cd.getTitle( ) + "' by " + cd.getArtist( ) + " on the label " + cd.getLabel( )); } } else { Fault fault = response.getFault( ); System.out.println("Error encountered: " + fault.getFaultString( )); Vector entries = fault.getDetailEntries( ); for (Iterator i = entries.iterator(); i.hasNext( ); ) { org.w3c.dom.Element entry = (org.w3c.dom.Element)i.next( ); System.out.println(entry.getFirstChild().getNodeValue( )); } } By using the getDetailEntries( ) method, you get access to the raw data supplied by the SOAP service and server about the problem. The code iterates through these (there is generally only a single element, but it pays to be careful) and grabs the DOM Element contained within each entry. Essentially, here's the XML you are working through: <SOAP-ENV:Fault> <faultcode>SOAP-ENV:Server.BadTargetObjectURI</faultcode> <faultstring>Unable to resolve target object: null</faultstring> <stacktrace> Here's what we want! </stackTrace> </SOAP-ENV:Fault> In other words, the Fault object gives you access to the portion of the SOAP envelope that deals with errors. Additionally, Apache SOAP provides a Java stack trace if errors occur, and that provides the detailed information needed to troubleshoot problems. By grabbing the stackTrace element and printing the Text node's value from that Element , your client will now print out the stack trace from the server. Compile these changes and rerun the client. You should get the following output: C:\javaxml2\build>java javaxml2.CDLister http://localhost:8080/soap/servlet/rpcr outer Listing current CD catalog. Error encountered: Unable to resolve target object: null java.lang.NullPointerException at javaxml2.CDCatalog.addCD(CDCatalog.java:24) at javaxml2.CDCatalog.<init>(CDCatalog.java:14) at java.lang.Class.newInstance0(Native Method) at java.lang.Class.newInstance(Class.java:237) This goes on for a bit, but you can see the juicy bits of information indicating that a NullPointerException occurred, and even get the line numbers on the server classes where the problems happened. The result of this fairly minor change is a much more robust means of handling errors. That should prepare you for tracking down bugs on your server classes. Oh, and be sure to change your CDCatalog class back to a version that won't cause these errors before moving on! What's Next? The next chapter is a direct continuation of these topics. More than ever, XML is becoming the cornerstone of business-to-business activity, and SOAP is key to that. In the next chapter, I'll introduce two important technologies to you, UDDI and WSDL. If you have no idea what those are, you're in the right place. You'll learn how they all fit together to form the backbone of web services architectures. Get ready to finally find out what the web services, peer-to-peer craze is all about. 1.There's a lot of talk about running SOAP over other protocols, like SMTP (or even Jabber). This isn't part of the SOAP standard, but it may be added in the future. Don't be surprised if you see it discussed. 2.You can use scripts through the Bean Scripting Framework, but for the sake of space I won't cover that here. Check out the upcoming O'Reilly SOAP book, as well as the online documentation at http://xml.apache.org/soap , for more details on script support in SOAP. Back to: Java & XML, 2nd Edition oreilly.com Home | O'Reilly Bookstores | How to Order | O'Reilly Contacts International | About O'Reilly | Affiliated Companies | Privacy Policy © 2001, O'Reilly & Associates, Inc. webmaster@oreilly.com



Spa Salt Scrub Cleanses

The Body Shop: Africa Spa Salt Scrub, africa, spa, salt, scrub, africa spa | | My Account | Login | Favorites | View Cart Body Butter Lotions Creams Other Moisturizers Hand Care Foot Care Massage Spa Scrubs Sun Care Accessories Gift Ideas Strawberry Bath Shower Soap Scrubs Accessories Gift Ideas Cleansers Toners Moisturizers Scrubs and Masks Treatments Lips Eye Care Make-up Removers Sun Care Accessories Palettes Lips Eyes Face Make-Up Tools Oils Aroma Jars Candles & Accessories Gift Ideas Eau de Toilette Perfume Oils Body Sprays Lotions Shower Bath Lifestyle Fragrances Invent Your Scent Gift Ideas Scent-Me Collection Shampoo Conditioner Treatment Styling Products Brushes Essential Oils Massage Lotions Bath & Shower Home Fragrance Bergamot Lavender Ylang-Ylang Mandarin Gift Ideas Shaving & Face Hair & Body Fragrance Accessories Massage Gift Ideas Bath Hair Brushes Hand & Foot Massage Skin Accessories Make-Up Tools Bags & Cases Support a Cause Books Gift Ideas Sign up to receive discounts and special offers. Africa Spa Salt Scrub Cleanses while exfoliating with Community Trade shea butter and organic beeswax. Skin is left extra smooth. Lightly perfumes, too. View Larger See More Details 13.5 oz. Africa Spa Salt Scrub 70505 Add to My Favorites List Temporarily Out of Stock Email Me When In Stock Find a Store We also recommend... Africa Spa Shower Cream More Details Key Ingredients All Ingredients Instructions Tip Zone Organic beeswax Moisturizes and helps to condition the hands and dry skin around the nail beds. Acts as a barrier that helps to seal in moisture. Helps to keep product texture consistent, when used over time. Helps protect and preserve the forest as well as providing necessary income for the beekeepers, an increasing number of which are now women. Shea butter Moisturizes and helps soften the skin. Also provides a rural community of women with regular work and income. Salt Gently exfoliates the skin. Glycerin Is an effective moisturizer which helps improve softness and maximize hydration. Community Trade Information Beeswax is a Community Trade ingredient from the remote tropical forests of North West Zambia, where the extra income helps more than 3,000 beekeepers preserve their traditional way of life. View More Shea butter is one of nature's great moisturizers. Ghanaian women have used it for centuries to protect their skin from the dry Saharan winds. So who better to buy ours from than the Tungteiya Shea Butter Association, Northern Ghana. An association of around 400 women from 10 villages, we ensure a fair price for their product. Since trading with The Body Shop the women have been able to dramatically change their lives with water pipes and wells saving hours of water collecting, better housing, medical care, food, and self esteem. Importantly, they are also able to give their children, particularly their daughters, the chance to go to school. View More Corporate Site | News | Employment Opportunities | The Body Shop Canada | The Body Shop UK | Terms & Conditions | Privacy Policy | About Us Affiliate Program | Store Locator | Site Map | Help | Contact Us Aromatherapy & Spa Gifts © 2005 The Body Shop International plc. All Rights Reserved.



Man Skin Care

Shopping at BizRate: Compare Prices, Product Reviews and Online Stores Log in to your account Bookmark this page! Home Home & Garden Computers Clothes Toys Electronics Kids Jewelry All Departments I'm shopping for in All Departments Appliances Automotive Babies & Kids Books & Magazines Clothing & Accessories Computers & Software DVDs & Videos Electronics Gifts, Flowers & Food Health & Beauty Supplies Home & Garden Jewelry & Watches Music Musical Instruments & Accessories Office Supplies Other Products Pet Supplies Sports Equipment & Outdoor Gear Toys & Games Video Games ---------------------- Special Offers Store Ratings Browse Valentine's Gifts For Her Heart Necklaces & Pendants Valentine's Day Roses La Perla Lingerie Valentine's Gifts For Him Valentine's Day Chocolates Portable DVD Players Boxers Valentine's Gifts For Kids Valentine's Day Candy Kingdom Hearts 2 Video Game for PlayStation 2 Valentine's Day Balloons & Teddy Bears Home & Garden Appliances Bedding Home Lighting Window Treatments Tableware More Computers & Software Laptop Computers Ink Cartridges Printers Memory Cards PDAs & Handheld Computers More Clothing & Accessories Men's Clothing Men's Shoes Sunglasses Women's Clothing Women's Shoes More Electronics Digital Cameras MP3 Players Televisions Camcorders GPS Devices More Jewelry & Watches Watches Rings Necklaces & Pendants Bracelets Earrings More Sports Equipment & Outdoor Gear Fitness Equipment Swimming Pools & Jacuzzis Golf Gifts & Equipment Camping & Hiking Gear Bicycles & Equipment More Health & Beauty Perfume & Cologne Skin Care Products Vitamins & Nutrition Cosmetics Hair Care More Furniture Living Room Bedroom Dining Room Kitchen Outdoor Furniture Other Departments Appliances Automotive Babies & Kids Books & Magazines DVDs & Videos Gifts, Flowers & Food Mature Music Musical Instruments Office Supplies Pet Supplies Services Toys & Games Travel & Leisure Video Games Store Ratings Special Offers Popular Searches See All Departments Buying Guides Digital Cameras Televisions MP3 & Media Players Laptop Computers Printers More Welcome to our free comparison shopping site! We'll help you: Find the biggest selection from the Web's top-rated stores. Compare product features, prices & reviews! Get the best deal every time! Watches Bulova Watches Movado Watches Tissot Watches More Digital Cameras Canon Digital Cameras Nikon Digital Cameras Kodak Digital Cameras More Women's Clothing Cocktail Dresses Swimsuits Diesel Jeans More Women's Shoes Pumps and High Heels Sandals Ugg Boots More Television Plasma Televisions LCD Televisions Rear-Projection Televisions More Handbags & Luggage Prada Handbags Gucci Handbags Tumi Luggage More MP3 & Media Players IPod Nano Zen Micro Sandisk Sansa More Furniture Sectional Sofas Platform Beds Dining Tables More Fitness Equipment Treadmills Elliptical Machines Exercise Bikes More Popular Digital Cameras Digital Cameras Buying Guide Canon PowerShot SD400 Price Range: $219 to $438 Kodak Easyshare Z-740 Price Range: $196 to $399 Casio Exilim EX-S500 Price Range: $264 to $399 Everything you need for your home Home Lighting Bedding Window Treatments Popular Televisions Television Buying Guide Panasonic TH-42PX50U 42 in Flat Screen Plasma TV Price Range: $2,390 to $2,999 Sony Wega KDF-E50A10 50 in LCD Flat Screen Rear-projection TV Price Range: $1,600 to $2,374 Syntax Olevia 37 in Flat Screen LCD TV Price Range: $1,403 to $1,748 Get great deals on jewelry Rings Bracelets Cuff Links Popular Laptops Laptop Computers Buying Guide Acer Aspire AS3003LCI 1.8 GHz Price Range: $574 to $799 Toshiba A55-S3063 1.5 GHz Pentium M Laptop Price Range: $795 to $1,149 Lenovo ThinkPad T23 1.13 GHz Pentium III Price Range: $479 to $629 See the 2005 Circle of Excellence Winners! Home | Help | About BizRate.com | Privacy Policy | User Agreement | Jobs Merchant Login | Merchant Listings and Advertising | Ratings and Research | Affiliates BizRate International - BizRate UK | BizRate France | BizRate Germany Check out our new site, Shopzilla.com - Take a Tour | Online Shopping Shopzilla International - United Kingdom , France , Germany Thank you for shopping online at BizRate © 2006 Shopzilla, Inc.



Spa Salt Scrub $24.00

Body Scrubs products at MSN Shopping MSN Home My MSN Hotmail Shopping Money People & Chat Sign In Web search: Shopping Save this page Feedback Site map Help Home | Beauty | Books | Clothing | Computers | Deals | Electronics | Flowers | Home & Garden | Jewelry | Movies | Music | More ... Search Shopping Home > Beauty & Fragrance > Bath & Spa Body Scrubs Advertisement Featured Stores See all stores Advertisement 2,613 items found Narrow your selection: Brand Peter Thomas Roth Bliss Aura Cacia Liz Claiborne Organic Bath Company Archipelago Botanicals philosophy Desert Essence More... Seller eBay.com NORDSTROM.com drugstore.com Life's Vigor Perfume Bay Beauty.com Sephora.com Spalook More... Price range $0 - $10 $10 - $20 $20 - $30 $30 - $40 $40 - $55 $55 - $101 $ to $ Show sale items only Calculated in 0.093 seconds Previous Page 1 2 3 4 5 6 7 8 9 10 of 175 Next View: List Grid Text checked items Sort by Most popular Highest user rating Lowest price Highest price Name A-Z Name Z-A Grapefruit Verbena Scented Sugar Scrub from Illuminations.com by Illuminations $12.00 A spa treatment at home. Pure cane sugar crystals are ... More blended with soothing oils and delicious fragrance. Apply to wet skin and gently massage, polishing away dead cells while leaving skin soft and glowing. Some fragrances were designed to energize, others to soothe. The carefully blended combination of our Grapefruit Verbena scented bath line captures the purest intentions of both. This scent features the bold citrus of grapefruit and the lip-puckering of lemon verbena. At 1 store | Details Rate it Organic Bath Body scrub Pomegranate Fig., 9oz. by Organic Bath Company $6.85 Body scrub Pomegranate Fig., 9oz. : Rich Exfoliating Body ... More ScrubDeeply clean and replenish the skin with crushed apricot and strawberry seeds blended with rich jojoba and apricot seed oil. This natural exfoliating scrub is loaded with healthy antioxid At WebVitamins.com | Details Rate it L'Occitane Lavender Harvest Velvet Body Scrub by L'Occitane $28.00 Rich and creamy, Velvet Body Scrub contains A.O.C. Lavender ... More essential oil, shea butter, and walnut kernel particles to gently remove dead surface cells on the body, elbows, knees, and feet. Skin is left smooth, soft, and deeply exfoliated. At Sephora.com | Details Free shipping on orders over $75 Rate it ZING Warming Body Scrub $13.10 The warming scrub helps to boost vital energy and it helps ... More to promote blood circulation in the system. The warming effects can lead to weight loss, relieving bloated ness, water retention throughout the body and energizing numb or cold limbs. Type: Powder At 1 store | Details Rate it Replenishing Body Polish, White Tea 15 oz by Organic Bath Company $9.50 Replenishing Body Polish - Renew, refine, and moisturize ... More with the ultimate Replenishing Body Polish. Organic White Tea, nature's own super anti-oxidant, and purifying salt will reveal truly beautiful, soft skin. At 1 store | Details Average rating Reviews Artemis Woman Healing Gems Tourmaline Body Polish $14.99 Treat yourself to a body polish that revitalizes with ... More aromatherapy. The Artemis Woman Healing Gems Body Polish contains pure essential oils and natural tourmaline crystals. Skin is refreshed and... body gems, Polish Gems, tourmaline pricing, Tourmaline Bath, Polish Body Spa, Tourmaline Gifts, Tourmaline Healing, Artemis Woman Body Polish At Target | Details Rate it L'Occitane Verbena Harvest Body Salt Scrub by L'Occitane $29.00 Salts from the Mediterranean Sea are combined with the ... More refreshing and calming scent of rich extracts of Verbena, lemon, and orange to form this luxurious, "spa style" salt scrub. The salts, combined with soothing essential oils, remove dry skin, increase circulation and leave your body soft and smooth. At Sephora.com | Details Free shipping on orders over $75 Rate it Africa Spa Salt Scrub $24.00 This luxurious Body Salt Scrub effectively cleanses and ... More exfoliates the skin. Salts gently exfoliate to revitalize dull skin and refine, leaving the skin soft and smooth. Fragranced with a subtle warm floral, fruity scent. At The Body Shop | Details Free Shipping on Orders Over $50 Rate it Sugar Scrub Body Exfoliant, 6.8 oz by Osmotics $32.00 This unique blend of natural sugar, lemon, loofah and rich ... More emollient oil banishes dry, rough skin, leaving it soft, silky and smooth. At Beauty.com | Details Free gift & free ship! Rate it Joe Glow Head-To-Toe Caffeinated Cleansing Scrub, 8.8 oz by Urban Decay $24.50 Joe Glow will get you glowing from head-to-toe with a ... More caffeine jolt, infusions of coffee, and the power of green tea. With an invigorating coffee and cream scent, Joe Glow Scrub awakens the senses and gently scrubs skin soft as it cleanses. At Beauty.com | Details Free gift & free ship! Rate it Buttercream Sugar Scrub, 5 oz by DuWop $24.00 Ready for dessert? This decadent body scrub not only smells ... More like buttercream frosting, it uses raw sugar to gently exfoliate your skin. The soft, glowing results will leave you craving seconds. At Beauty.com | Details Free gift & free ship! Rate it Hot Salt Scrub, Rosemary + Eucalyptus, 19.4 oz by Bliss $36.00 This legendary, all-over sea salt body scrub is oil-free, ... More super-softening, self-heating, and spiked with eucalyptus and rosemary oils. At Beauty.com | Details Free gift & free ship! Rate it Soap 'n Scrub, Super Minty, 8 fl oz by Bliss $30.00 loaded with blue jojoba beads (that work like little ... More loofahs) and a bracing blend of peppermint oil and menthol (for a truly formidable level of 'frisk'). At Beauty.com | Details Free gift & free ship! Rate it Body Scrub, Wild Rice and Oatmeal, 6.7 fl oz by Te Tao $5.99 Wild Rice and Oatmeal Body Polish is a luxurious ... More exfoliating gel, which removes impurities, improves skin texture and aids circulation. At drugstore.com | Details Free gift & free ship! Rate it Gentle Body Exfoliator Tranquil Wash, 6.8 fl oz by Ahava $16.00 This delicate Body Wash gently exfoliates and cleanses the ... More skin, leaving it revitalized, softer and silkier. At drugstore.com | Details Free gift & free ship! Rate it checked items Sort by Most popular Highest user rating Lowest price Highest price Name A-Z Name Z-A Previous Page 1 2 3 4 5 6 7 8 9 10 of 175 Next View: List Grid Text What's this? Search Shopping Shopping help About this site FAQ Newsletter sign-up Trends & deals Home Baby Beauty Books Car & Garage Clothing Computer Deals Electronics Flowers Furnishings Garden Gifts Health Jewelry Kitchen Movies Music Office Pets Shoes Sports Toys Video Games ©2006 Microsoft Legal MSN Privacy Advertise Images credit: Getty Images Feedback



Google

 Home

 Skin Care

 skin care anti-aging cosmetics

 skin care Virtual makeovers

 Skin Care Hand &

 Skin Care | Shopping

 Skin Care Products Store

 Skin Care

 Skin Care Kit. Men's

 Skin Care and Aging

 Skin Care Written by

 Skin Care Email this

 skin care products, but

 skin care treatments. Sun

 Skin Care Diabetes can

 Skin Care delivers the

 Skin Care

 Skin Care Microdermabrasion Creams

 skin care products line

 Skin Care Smooth Sailing

 Skin Care

 Skin Care Articles Teens

 Skin Care

 Skin Care A Complete

 Skin Care Visit our

 skin care products are

 Skin Care and Beauty

 Skin Care Products, Skincare

 skin care facial care

 Skin Care Products Take

 skin care, Chemical free

 Skin Care Read reviews

 Skin Care Products ----------------------

 Skin care for transgendered

 Skin Care Professionals Responding

 Skin Care Become an

 skin care facial care

 Lotion Price: $18.95 Quantity:

 Lotion Samples, Catalogs, Discounts

 Lotion USP, 1% You

 Lotion 1. Set up

 Lotion Bar Tubes Lotion

 LOTION forthe SAFEST, FASTEST,MOST

 Lotion Body Bronzing Lotion

 lotion that acts as

 Lotion Skip Sub-site Navigation

 Lotion/Moisturizer Bath & Body

 Lotion Table of Contents

 Lotion

 lotion, hemp hand lotion,

 Lotions Creams Other Moisturizers

 Lotion for Noevir Packaging

 Lotion Tanning Refine these

 Lotion for Military to

 Lotion Important - Always

 Lotion St. Tropez Self

 Lotion by Sauve Style

 lotionmaking * perfuming *

 Lotion Face & Body

 Lotion Questions and Answers

 Lotions Creams Other Moisturizers

 Lotions Creams Other Moisturizers

 Lotions Creams Other Moisturizers

 Lotion SPF 15 Click

 lotions enriched with Sweet

 Lotions Creams Other Moisturizers

 Lotions Creams Other Moisturizers

 Lotions Creams Other Moisturizers

 Lotion) Item Number: 82160

 Lotion SPF 30 Item

 Lotion Login/Register | How

 Lotion About Our Scoring

 lotion, sun, skin care

 Lotion on Flights Your

 Lotion Massage & Relaxation

 Lotion Other products by

 Lotion, Pump Top (33.6

 Lotion, Regular 3-Pack, 3-Ply

 Lotion - Hamptons Hideaway

 Lotion Previous Next Sizes:

 Lotion Item Number: 90169

 Lotion Other products by

 Lotion from CornerMark Essential

 Lotion Pain Relief .

 Lotion LP Live LP

 Sun Tan Lotion

 Sun Tan Lotion

 Sun Tan Lotion

 Sun tan lotion that

 Sun Tan Lotion

 Sun Tan Lotion

 Sun Tan Lotion

 Sun Tan Lotion

 Sun Tan Lotion

 Sun Tan Lotion

 Sun Tan Lotion

 Sun Tan Lotion -

 Sun Tan Lotion

 Sun Tan lotion tan

 Sun Tan Lotion

 Sun Tan Lotion

new age healing Treadmills Weight Loss enzyme aromatherapy information
Free Link Exchange