Face Scrub
The Body Shop: Soy & Calendula Gentle Facial Scrub, soy & calendula, soy, calendula, facial, scrub, face, skin care | | 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. Scrubs and Masks Best Sellers Vitamin E Nourishing Night Cream Vitamin E Moisture Cream Chamomile Gentle Eye Make-Up Remover Tea Tree Oil Facial Wash 24-Hour Treatment Lotion with Kinetin Soy & Calendula Gentle Facial Scrub Tiny mineral beads gently exfoliate to reveal smoother, softer skin. View Larger See More Details 2.5 fl. oz. Soy & Calendula Gentle Facial Scrub 68572 Add to My Favorites List $12.00 Quantity Other Recommended Categories Dry or sensitive skin We also recommend... Soy & Calendula Gentle Cleanser Soy & Calendula Soothing Moisturizer SPF 15 More Details Key Ingredients All Ingredients Instructions Tip Zone Calendula Soothes the skin. Glycerin Is an effective moisturizer which helps improve softness and maximize hydration. Lavender essential oil Is known to relax and calm. Is renowned for helping to soothe the skin. Has a soothing herbal and floral scent. Is known to help soothe the mind and promote restful sleep. Helps to moisturize the skin. Organic soya oil Is very rich in essential fatty acids that help to repair the skin's moisture barrier, thus helping to restore moisture, smoothness and suppleness. Also helps a group of around 500 farmers maintain their organic agriculture. 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 Scrubs and Masks | © 2005 The Body Shop International plc. All Rights Reserved. face scrub for menClinique Face Scrub for Men Review in Mens Cosmetics at Review Centre Clinique Face Scrub for Men Login/Register | How Can You Help? Reviews Beauty Forums Topic : Please select Books Cameras Cars Computers Electronics Entertainment Fashion & Lifestyle Finance Games Home & Garden Phones Sport Travel Websites this topic Review Centre Fashion & Lifestyle Hair and Beauty Mens Cosmetics clinique face scrub for men If you have a picture of Clinique Face Scrub for Men, please click this link to send it. overview reviews resources Clinique Face Scrub for Men Prices Clinique Skin Supplies For Men Great Shave Coffret: Face Scrub+ Cream Shave+ Post Shave Healer 3pcs by Clinique StrawberryNET £27.33 Face Scrub - Clinique For Men 100ml Supadrugstore.com £13.99 Clinique For Men Face Scrub Size: 100ml Pharmacy 2 U £13.50 1 Clinique Face Scrub for Men Review Review by festusbodine on 9th Apr 2004 User Rating: 8 Respect: 0 I used Clinique Face Scrub for Men years ago and recently came back to it. I also have the Clarins men scrub, but I like the Clinique scrub more - it's more "scrubby." The Clarins one has too few gr ... read full review Clinique Face Scrub for Men Resources Aftershave Hair Loss Shaving Aftershaves at Shopping.com Aftershaves at Dealtime.co.uk Find Great Deals on Aftershave Buy Discounted Aftershaves Online Related categories Compare Face Masks and Treatments Currently raised : £ 2872.50 Top Picks Anthony Logistics For Men Sea Salt Body Scrub Helmut Lang Shower Gel for Men Clinique Non-Streak Bronzer for Men Maxwells Apothecary Razor Relief Phytomer: Lift Contour Anti-Ageing Eye Cream Online Shops Back Massagers Beauty Cosmetic Surgery Hair Magazines Hair Styles Health Farms & Spas Henna Tatoos Model Agencies Nail Extensions Tooth Whitening Resources Select Your Location Top Pick Clinique Face Scrub for Men £13.5 Click Here for details See all 3 offers Consumer Reviews in © 1999-2006 Botox Treatment Center |Botox About Us | Privacy Policy MedicineNet Home Procedures & Tests A-Z List Skin Home Page Botox Treatment search help Printer-Friendly Format | Email to a Friend 1 Botox Treatment Center | Next Botox How Does Botox Work? How Is The Botox Procedure Performed? How Long Does A Botox Injection Last? What Are The Side Effects Of Botox? Who Should Not Receive Botox Injection? Will My Insurance Pay For Botox Injections? Botox is the brand name of a toxin produced by the bacterium Clostridium botulinum . In large amounts, this toxin can cause botulism , which you probably associate with food poisoning . Despite the fact that one of the most serious complications of botulism is paralysis, scientists have discovered a way to use it to human advantage. Small, diluted amounts can be directly injected into specific muscles causing controlled weakening of the muscles. The FDA approved such usage in the late 1980s upon the discovery that Botox could stop ailments like blepharospasm (uncontrolled blinking) and strabismus (lazy eye). Cosmetic physicians have been using Botox for years to successfully treat wrinkles and facial creases. In April 2002, Botox gained FDA approval for treatment of moderate-to-severe frown lines between the eyebrows - called glabellar lines. However, Botox is often used for other areas of the face as well. How Does Botox Work? Botox blocks signals from the nerves to the muscles. The injected muscle can no longer contract, which causes the wrinkles to relax and soften. It is most often used on forehead lines, crow's feet (lines around the eye) and frown lines. Wrinkles caused by sun damage and gravity will not respond to Botox. How Is the Procedure Performed? The procedure takes only a few minutes and no anesthesia is required. Botox is injected with a fine needle into specific muscles with only minor discomfort. It generally takes three to seven days to take full effect and it is best to avoid alcohol at least one week prior to treatment. Aspirin and anti-inflammatory medications should be stopped two weeks before treatment as well in order to reduce bruising. How Long Does a Botox Injection Last? The effects from Botox will last four to six months. As muscle action gradually returns, the lines and wrinkles begin to re-appear and wrinkles need to be re-treated. The lines and wrinkles often appear less severe with time because the muscles are being trained to relax. What Are the Side Effects of Botox? Temporary bruising is the most common side effect. Headaches, which resolve in 24-48 hours, can occur, but this is rare. A small percentage of patients may develop eyelid drooping. This usually resolves in three weeks. This development is usually caused by migration of the Botox and for this reason, you shouldn't rub the treated area for 12 hours after injection or lay down for three to four hours. There have been no allergies associated with Botox to date. Who Should Not Receive Botox Injection? Patients who are pregnant, breastfeeding or have a neurological disease should not use Botox. Since Botox doesn't work for all wrinkles, a consultation with a doctor is recommended. Will My Insurance Pay For It? Insurance coverage varies for Botox injections, depending largely on the medical necessity of your condition. Botox is not generally covered by insurance when used for cosmetic purposes. Check with your insurance carrier for coverage details. Reviewed by the doctors at The Cleveland Clinic, Department of Dermatology Edited by Charlotte E. Grayson, MD , Sept. 2003. Portions of this page The Cleveland Clinic 2000-2003 1 Botox Treatment Center | Next From the Doctors at MedicineNet.com Migraine Headache - Medical explanation of migraine headaches; includes symptoms, diagnosis, treatments with and without medication, description of medications, prevention, and common triggers. Source:MedicineNet Body Dysmorphic Disorder - People with body dysmorphic disorder (BDD) are obsessed by the idea that some part of their body -- their hair, nose, skin, hips, whatever -- is ugly or deformed, when in truth it looks normal. Source:Government Wrinkles - Wrinkles appear as skin ages. There are two categories of wrinkles, surface lines and deep furrows. Source:MedicineNet Read 16 more Botox Treatment related articles ... How Many Young Women Get Plastic Surgery? Whats the Most Popular Cosmetic Procedure? Health Tip: Choosing a Cosmetic Surgeon Printer-Friendly Format | Email to a Friend Last Editorial Review: 2/8/2005 Visit The Skin Home Page Browse related topics: - Botox Treatment Allergies Alzheimer's Arthritis Asthma BloodPressure Cancer Cholesterol Chronic Pain Cold & Flu Crohn'sDisease Depression Diabetes Dictionary Digestion Eyesight Feet &Fitness First Aid Healthy Kids HealthyLiving Hearing & Ear Heart Hepatitis C HIV/AIDS Liver Lung Cond. Medications Menopause Men's Health Mental Health Migraine Osteoporosis Rheum.Arthritis Senior Health Skin Sleep Thyroid Urology WeightMgmt. Women'sHealth 650+More Topics Hair Loss Restless Leg Syndrome Dizziness Chest Pain Palpitations Lipitor (atorvastatin) Tenormin (atenolol) Glucophage (metformin) Plavix (clopidogrel) Coumadin (warfarin) Stress Cholesterol High Blood Pressure Congestive Heart Failure Stroke Free Newsletters Download (PDF) Reports Audio Medical Podcasts Find a Therapist by Psychology Today Meet the Doctors Site Map Skin News via RSS January 26, 2006 Topics Related to Botox Treatment Doctors' Views Doctor: Getting the Most from Your Doctors Appointment How to Choose a Doctor Medications botulinum toxin type A, Botox, Botox Cosmetic Procedures & Tests Neck Lift Cosmetic Surgery Lip Augmentation more>> Diseases & Conditions Migraine Headache Body Dysmorphic Disorder more>> Health Facts Doctor: Checklist to Take To Your Doctor's Appointment Cosmetic Surgery: Questions to Ask Your Doctor About Plastic Surgery Health News How Many Young Women Get Plastic Surgery? Whats the Most Popular Cosmetic Procedure? more>> Botox Treatment - Specialty What is this? Health A to Z lists: News & Views | Diseases & Conditions | Symptoms & Signs | Procedures & Tests | Medications | Medical Dictionary Popular health centers: Allergies | Arthritis | Cancer | Diabetes | Digestion | Healthy Kids | Heart | Men's Health | Mental Health | Women's Health | More... Publications: ePublications (PDFs) | XML News via RSS | Audio Newsletters & Podcasts | Email Newsletters MedicineNet.com: About Us | Privacy Policy | Help | Search | Site Map 1996-2006 MedicineNet, Inc. All rights reserved. Notices and Legal Disclaimer. Information on this web site is provided for informational purposes only and is not a substitute for professional medical advice. You should not use the information on this web site for diagnosing or treating a medical or health condition. You should carefully read all product packaging. If you have or suspect you have a medical problem, promptly contact your professional healthcare provider. Statements and information regarding dietary supplements have not been evaluated or approved by the Food and Drug Administration. Please consult your healthcare provider before beginning any course of supplementation or treatment. bath salts at homeDead Sea Salt & Bath Salts - Bathing 800-353-7258 Dead Sea Salt Bathing Dead Sea Salt Bathing: The beneficial effects of the Dead Sea Salts on the skin and their unique therapeutic and beautifying powers have been recognized since ancient times. Cleopatra, considered the most beautiful woman in the world, went to great expense to obtain exclusive rights over the Dead Sea area. At her command, pharmaceutical and cosmetic factories were built near the Dead Sea. Their remains can still be seen today at Ein Bokek and Ein Gedi. The use of Dead Sea bath salts at home is an effective way to relax and absorb the minerals of the Dead Sea. Research has proven the efficiency of Dead Sea bath salts in alleviating skin diseases such as psoriasis, by treatment that can be administered at home by using about 2 lbs. for each bath. It is also highly beneficial for relieving muscle tension or for simply relaxing and enjoying a rejuvenating experience. Theres nothing like a soak in a Dead Sea Salt bath. This practice was once relegated to high-end spas and expensive skin clinic, but now therapeutic salt baths are becoming common practice in homes all across America. A Sea Salt bath provides a medium for deep relaxation, as well as a feast of minerals for the skin. BOKEK Dead Sea Salts contain all the minerals of the Dead Sea. Soaking in a bath with Dead Sea Salt is a powerful remedy for healthy skin. At SaltWorks we have long believed in the power Dead Sea Salt baths. We recommend bathing in BOKEK Dead Sea Salt as one of the primary ways of relaxing, detoxifying, and treating disease. For treatment of illnesses, we recommend adding two pounds of salt to a lukewarm bath. This much is necessary to start changing the skins chemistry. The temperature of a healing bath should only be about 2 degrees warmer than the temperature of your body. Hot bath water causes the skin to eliminate instead of absorb, therefore the minerals of the salt cannot be absorbed into the body; instead they are eliminated. If you want to use salt baths on a regular basis to maintain good health, it is not necessary to use 2 pounds of salt. In using the BOKEK Dead Sea Salts , we recommend two handfuls. This is enough salt to feed the body with minerals and maintain a condition of good health. You can buy BOKEK Dead Sea Salt in our online store ! Salt Resource Center General Information: What is Salt? History of Salt Consumer Tips for Salt Use Health Related: Salt and Good Health Salt and Human Health Balneotherapy (bath) Treatment Salt for Human Nutrition Cooking / Culinary Related: Gourmet Salt Reference Guide What is Organic Salt? Salt in Food Gourmet Salt Wholesale Salt Bath and Spa Related: Dead Sea Salt Bathing Bath Salt Therapy Water Therapy Making Bath Salts Benefits of Bokek Dead Sea Salt Dead Sea Related: About the Dead Sea The Use of Dead Sea Salt Benefits of Dead Sea Salt Sign up to receive recipes and special offers on bath and gourmet sea salt: site map | privacy policy | ©2001 - 2006 SaltWorks, 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 |
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 |