Translate

Monday, September 17, 2012

JAX-WS Hello World Example – RPC Style


JAX-WS Hello World Example – RPC Style

By - November 16, 2010
Source: http://www.mkyong.com/webservices/jax-ws/jax-ws-hello-world-example/
JAX-WS is bundled with JDK 1.6, which makes Java web service development easier to develop. This tutorial shows you how to do the following tasks:
  1. Create a SOAP-based RPC style web service endpoint by using JAX-WS.
  2. Create a Java web service client manually.
  3. Create a Java web service client via wsimport tool.
  4. Create a Ruby web service client.
You will be surprise of how simple it is to develop a RPC style web service in JAX-WS.
Note
In general words, “web service endpoint” is a service which published outside for user to access; where “web service client” is the party who access the published service.

JAX-WS Web Service End Point

The following steps showing how to use JAX-WS to create a RPC style web service endpoint.

1. Create a Web Service Endpoint Interface

File : HelloWorld.java
package com.mkyong.ws;
 
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
 
//Service Endpoint Interface
@WebService
@SOAPBinding(style = Style.RPC)
public interface HelloWorld{
 
 @WebMethod String getHelloWorldAsString(String name);
 
}

2. Create a Web Service Endpoint Implementation

File : HelloWorldImpl.java
package com.mkyong.ws;
 
import javax.jws.WebService;
 
//Service Implementation
@WebService(endpointInterface = "com.mkyong.ws.HelloWorld")
public class HelloWorldImpl implements HelloWorld{
 
 @Override
 public String getHelloWorldAsString(String name) {
  return "Hello World JAX-WS " + name;
 }
 
}

3. Create a Endpoint Publisher

File : HelloWorldPublisher.java
package com.mkyong.endpoint;
 
import javax.xml.ws.Endpoint;
import com.mkyong.ws.HelloWorldImpl;
 
//Endpoint publisher
public class HelloWorldPublisher{
 
 public static void main(String[] args) {
    Endpoint.publish("http://localhost:9999/ws/hello", new HelloWorldImpl());
    }
 
}
Run the endpoint publisher, and your “hello world web service” is deployed in URL “http://localhost:9999/ws/hello“.

4. Test It

You can test the deployed web service by accessing the generated WSDL (Web Service Definition Language) document via this URL “http://localhost:9999/ws/hello?wsdl” .

Web Service Clients

Ok, web service is deployed properly, now let’s see how to create web service client to access to the published service.

1. Java Web Service Client

Without tool, you can create a Java web service client like this :
package com.mkyong.client;
 
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import com.mkyong.ws.HelloWorld;
 
public class HelloWorldClient{
 
 public static void main(String[] args) throws Exception {
 
 URL url = new URL("http://localhost:9999/ws/hello?wsdl");
 
        //1st argument service URI, refer to wsdl document above
 //2nd argument is service name, refer to wsdl document above
        QName qname = new QName("http://ws.mkyong.com/", "HelloWorldImplService");
 
        Service service = Service.create(url, qname);
 
        HelloWorld hello = service.getPort(HelloWorld.class);
 
        System.out.println(hello.getHelloWorldAsString("mkyong"));
 
    }
 
}
Output
Hello World JAX-WS mkyong

2. Java Web Service Client via wsimport tool

Alternative, you can use “wsimport” tool to parse the published wsdl file, and generate necessary client files (stub) to access the published web service.
Where is wsimport?
This wsimport tool is bundle with the JDK, you can find it at “JDK_PATH/bin” folder.
Issue “wsimport” command.
wsimport -keep http://localhost:9999/ws/hello?wsdl
It will generate necessary client files, which is depends on the provided wsdl file. In this case, it will generate one interface and one service implementation file.
File : HelloWorld.java
package com.mkyong.ws;
 
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
 
/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.1.1 in JDK 6
 * Generated source version: 2.1
 * 
 */
@WebService(name = "HelloWorld", targetNamespace = "http://ws.mkyong.com/")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface HelloWorld {
 
    /**
     * 
     * @param arg0
     * @return
     *     returns java.lang.String
     */
    @WebMethod
    @WebResult(partName = "return")
    public String getHelloWorldAsString(
        @WebParam(name = "arg0", partName = "arg0")
        String arg0);
 
}
File : HelloWorldImplService.java
package com.mkyong.ws;
 
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceFeature;
 
/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.1.1 in JDK 6
 * Generated source version: 2.1
 * 
 */
@WebServiceClient(name = "HelloWorldImplService", 
 targetNamespace = "http://ws.mkyong.com/", 
 wsdlLocation = "http://localhost:9999/ws/hello?wsdl")
public class HelloWorldImplService
    extends Service
{
 
    private final static URL HELLOWORLDIMPLSERVICE_WSDL_LOCATION;
 
    static {
        URL url = null;
        try {
            url = new URL("http://localhost:9999/ws/hello?wsdl");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        HELLOWORLDIMPLSERVICE_WSDL_LOCATION = url;
    }
 
    public HelloWorldImplService(URL wsdlLocation, QName serviceName) {
        super(wsdlLocation, serviceName);
    }
 
    public HelloWorldImplService() {
        super(HELLOWORLDIMPLSERVICE_WSDL_LOCATION, 
   new QName("http://ws.mkyong.com/", "HelloWorldImplService"));
    }
 
    /**
     * 
     * @return
     *     returns HelloWorld
     */
    @WebEndpoint(name = "HelloWorldImplPort")
    public HelloWorld getHelloWorldImplPort() {
        return (HelloWorld)super.getPort(
   new QName("http://ws.mkyong.com/", "HelloWorldImplPort"), 
   HelloWorld.class);
    }
 
    /**
     * 
     * @param features
     *  A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  
     *  Supported features not in the <code>features</code> parameter will have their default values.
     * @return
     *  returns HelloWorld
     */
    @WebEndpoint(name = "HelloWorldImplPort")
    public HelloWorld getHelloWorldImplPort(WebServiceFeature... features) {
        return (HelloWorld)super.getPort(
   new QName("http://ws.mkyong.com/", "HelloWorldImplPort"), 
   HelloWorld.class, 
   features);
    }
 
}
Now, create a Java web service client which depends on the above generated files.
package com.mkyong.client;
 
import com.mkyong.ws.HelloWorld;
import com.mkyong.ws.HelloWorldImplService;
 
public class HelloWorldClient{
 
 public static void main(String[] args) {
 
  HelloWorldImplService helloService = new HelloWorldImplService();
  HelloWorld hello = helloService.getHelloWorldImplPort();
 
  System.out.println(hello.getHelloWorldAsString("mkyong"));
 
    }
 
}
Here’s the output
Hello World JAX-WS mkyong

3. Ruby Web Service Client

Often time, web service development is mixed use with other programming language. So, here’s a Ruby web service client example, which is used to access the published JAX-WS service.
# package for SOAP-based services
require 'soap/wsdlDriver'
 
wsdl_url = 'http://localhost:9999/ws/hello?wsdl'
 
service = SOAP::WSDLDriverFactory.new(wsdl_url).create_rpc_driver
 
# Invoke service operations.
data1 = service.getHelloWorldAsString('mkyong')
 
# Output results.
puts "getHelloWorldAsString : #{data1}"
Output
getHelloWorldAsString : Hello World JAX-WS mkyong

Tracing SOAP Traffic

From top to bottom, showing how SOAP envelope flows between client and server. See #1 web service client again :
    URL url = new URL("http://localhost:9999/ws/hello?wsdl");
    QName qname = new QName("http://ws.mkyong.com/", "HelloWorldImplService");
    Service service = Service.create(url, qname);
 
    HelloWorld hello = service.getPort(HelloWorld.class);
 
    System.out.println(hello.getHelloWorldAsString("mkyong"));
Note
To monitor SOAP traffic is very easy, see this guide – “How to trace SOAP message in Eclipse IDE“.

1. Request a WSDL file

First, client send a wsdl request to service endpoint, see HTTP traffic below :
Client send request :
GET /ws/hello?wsdl HTTP/1.1
User-Agent: Java/1.6.0_13
Host: localhost:9999
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Server send response :
HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml;charset=utf-8
 
<?xml version="1.0" encoding="UTF-8"?>
 
<definitions 
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
 xmlns:tns="http://ws.mkyong.com/" 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
 xmlns="http://schemas.xmlsoap.org/wsdl/" 
 targetNamespace="http://ws.mkyong.com/" 
 name="HelloWorldImplService">
 
 <types></types>
 
<message name="getHelloWorldAsString">
 <part name="arg0" type="xsd:string"></part>
</message>
<message name="getHelloWorldAsStringResponse">
 <part name="return" type="xsd:string"></part>
</message>
 
<portType name="HelloWorld">
 <operation name="getHelloWorldAsString" parameterOrder="arg0">
  <input message="tns:getHelloWorldAsString"></input>
  <output message="tns:getHelloWorldAsStringResponse"></output>
 </operation>
</portType>
 
<binding name="HelloWorldImplPortBinding" type="tns:HelloWorld">
 
 <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"></soap:binding>
 <operation name="getHelloWorldAsString">
  <soap:operation soapAction=""></soap:operation>
  <input>
   <soap:body use="literal" namespace="http://ws.mkyong.com/"></soap:body>
  </input>
  <output>
   <soap:body use="literal" namespace="http://ws.mkyong.com/"></soap:body>
  </output>
 </operation>
 
</binding>
 
<service name="HelloWorldImplService">
<port name="HelloWorldImplPort" binding="tns:HelloWorldImplPortBinding">
<soap:address location="http://localhost:9999/ws/hello"></soap:address>
</port>
</service>
</definitions>

2. hello.getHelloWorldAsString()

A second call, client put method invoke request in SOAP envelope and send it to service endpoint. At the service endpoint, call the requested method and put the result in a SOAP envelope and send it back to client.
Client send request :
POST /ws/hello HTTP/1.1
SOAPAction: ""
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Content-Type: text/xml; charset=utf-8
User-Agent: Java/1.6.0_13
Host: localhost:9999
Connection: keep-alive
Content-Length: 224
 
<?xml version="1.0" ?>
 <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  <S:Body>
   <ns2:getHelloWorldAsString xmlns:ns2="http://ws.mkyong.com/">
    <arg0>mkyong</arg0>
   </ns2:getHelloWorldAsString>
  </S:Body>
 </S:Envelope>
Server send response :
HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml; charset=utf-8
 
<?xml version="1.0" ?>
 <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  <S:Body>
   <ns2:getHelloWorldAsStringResponse xmlns:ns2="http://ws.mkyong.com/">
    <return>Hello World JAX-WS mkyong</return>
   </ns2:getHelloWorldAsStringResponse>
  </S:Body>
 </S:Envelope>

Download Source Code

Download It – JAX-WS-HelloWorld-RPC-Example.zip (14KB)

Top 8 Java People You Should Know

Source: http://www.mkyong.com/featured/top-8-java-people-you-should-know/

Here are the top 8 Java people, they’re created frameworks, products, tools or books that contributed to the Java community, and changed the way of coding Java.
P.S The order is based on my personal priority.

8. Tomcat & Ant Founder

James-Duncan-Davidson
James Duncan Davidson, while he was software engineer at Sun Microsystems (1997–2001), created Tomcat Java-based web server, still widely use in most of the Java web projects, and also Ant build tool, which uses XML to describe the build process and its dependencies, which is still the de facto standard for building Java-based Web applications.

7. Test Driven Development & JUnit Founder

Kent-Beck
Kent Beck, creator of the Extreme Programming and Test Driven Development software development methodologies. Furthermore, he and Erich Gamma created JUnit, a simple testing framework, which turn into the de facto standard for testing Java-based Web applications. The combine of JUnit and Test Driven Development makes a big changed on the way of coding Java, which causes many Java developers are not willing to follow it.

6. Java Collections Framework

Joshua-Bloch
Joshua Bloch, led the design and implementation of numerous Java platform features, including JDK 5.0 language enhancements and the award-winning Java Collections Framework. In June 2004 he left Sun and became Chief Java Architect at Google. Furthermore, he won the prestigious Jolt Award from Software Development Magazine for his book, “Effective Java”, which is arguably a must read Java’s book.

5. JBoss Founder

Marc-Fleury
Marc Fleury, who founded JBoss in 2001, an open-source Java application server, arguably the de facto standard for deploying Java-based Web applications. Later he sold the JBoss to RedHat, and joined RedHat to continue support on the JBoss development. On 9 February 2007, he decided to leave Red Hat to pursue other personal interests, such as teaching, research in biology, music and his family.

4. Struts Founder

Craig-McClanahan
Craig Mcclanahan, creator of Struts, a popular open source MVC framework for building Java-based web applications, which is arguably that every Java developer know how to code Struts. With the huge success of Struts in early day, it’s widely implemented in every single of the old Java web application project.

3. Spring Founder

Rod-Johnson
Rod Johnson, is the founder of the Spring Framework, an open source application framework for Java, Creator of Spring, CEO at SpringSource. Furthermore, Rod’s best-selling Expert One-on-One J2EE Design and Development (2002) was one of the most influential books ever published on J2EE.

2. Hibernate Founder

gravin-king
Gavin King, is the founder of the Hibernate project, a popular object/relational persistence solution for Java, and the creator of Seam, an application framework for Java EE 5. Furthermore, he contributed heavily to the design of EJB 3.0 and JPA.

1. Father of the Java programming language

James-Gosling
James Gosling, generally credited as the inventor of the Java programming language in 1994. He created the original design of Java and implemented its original compiler and virtual machine. For this achievement he was elected to the United States National Academy of Engineering. On April 2, 2010, he left Sun Microsystems which had recently been acquired by the Oracle Corporation. Regarding why he left, Gosling wrote on his blog that “Just about anything I could say that would be accurate and honest would do more harm than good.”






Sunday, September 16, 2012

Web Container / Web Server / HTTP Server


Web Container : 
  • In J2EE Architecture, a web container(also known as servlet container or servlet engine), is used to manage the components like servletsJSP.
  • It provides a runtime environment to the components of J2EE.
  • When ever web server receive a request it forward it to web container which deals with it by instantiating,initializing and invoking Servlets and JSP pages. So,basically it controls the whole life cycle of servlet and JSP. 
  • It is a part of the web server.
  • Example: Apache Tomcat.

Web Server / HTTP Server :
  • It is a server which is capable of handling HTTP request send by a client and respond back with a HTTP respond.
  • Example: Apache Web Server.

Application Server / App Server :
  • It can handle all application operations between users and an organization's back end business applications or databases.
  • It's for complex transaction-based application.
  • It is frequently viewed as part of a three-tier application, where top-most tier is Presentation tier(GUI layer), then the Logic tier(an Application Server) and Data tier(consist of database server).
  • Example: IBM - WebSphere Application Server.

3 Laws of Good Software Architecture


Source: http://niklasschlimm.blogspot.com/2012/05/5-on-it-architecture-three-laws-of-good.html

3 laws of good software architecture

The issue with architectural decisions is that they effect the whole system and/or you often need to make them early in the development process. It means a lot effort if you change that decision a couple of months later. From an economic standpoint architectural decisions are often irrevocable. Good architecture is one that allows an architect to make late decisions without superior effect on efforts and costs. Let's put that on record.

Law 1: Good architecture is one that enables architects to have a minimum of irrevocable decisions.

To minimize the set of irrevocable decisions the system needs to be responsive to change. There is a major lesson I have learned about software development projects: Nothing is permanent except change. The client changes his opinion about requirements. The stakeholders change their viewpoint of what's important. People join and leave the project team. The fact that change alone is unchanging leads me to the second rule of good architecture, that is:

Law 2: To make decisions revocable you need to design for flexibility.

This is the most provocative statement and I am having controversial discussions here. The reason is that flexibility introduces the need for abstraction. Abstraction uses a strategy of simplification, wherein formerly concrete details are left ambiguous, vague, or undefined (from Wikipedia). This simplification process isn't always simple to do and to follow for others in particular. "Making something easy to change makes the overall system a little more complex, and making everything easy to change makes the entire system very complex. Complexity is what makes software hard to change." from M. Fowler) This is one core problem of building good software architecture: Developing software that is easy to change but at the same time understandable. There are several concepts that try to tackle this paradox problem: design patterns and object oriented design principles. Polymorphism, loose coupling and high cohesion are flexibility enablers to me.

Law 3: To make use of flexibility one needs to refactor mercilessly.

Flexibility is not an end in itself. You need to actively make use of flexible design. If something is changing and it makes a previous design or architectural decision obsolete you need to go into the code and change the software. Otherwise the effort of building flexible software is useless and technical debt may cause late delays and a maintenance nightmare. The fact that you take rigorous action on your code base requires continuous feedback about the qualities of your software. To be able to refactor it is therefore essential that the code base is covered by a sufficient amount of automated tests. In an ideal scenario everything is integrated into a continuous integration environment to receive permanent feedback about the health of your code base.

Overview of Single vs. Multi-Server Architecture


The Components

There are a number of competing components used in server setup, and for this discussion which component specifically used is not especially interesting. To be more specific
  • When I refer to Nginx, it could actually be any lightweight http server. That could mean Lighttpd or even a stripped down Apache instance.
  • When I refer to Apache and mod_wsgi, that could be Apache and mod_python, or even Nginx running FCGI. It's any server which is serving Django projects.
  • Postgres is my relational database of choice, but you could substitute it with MySQL or SQLite. Hell, you could even be using CouchDB for the extent of this discussion.
  • For caching I mention memcached, which doesn't have many direct competitors, but to the extent that they exist, they could be used interchangeably.

The Single-Server Approach

The simplest approach to serving a Django project is to configure one server to serve both dynamic (Django rendered pages) and static content (images, CSS, JavaScript, etc).
Single server layout for serving Django projects.
The biggest advantage of this single-server approach is in its simplicity. Especially Apache--but other systems as well--is very quick and painless to setup for a configuration like above (I find Nginx and fcgi a bit less straight forward, but certainly doable as well).
Another advantage is that you only need to run one server at a time, and servers can hog memory and cpu, especially on low powered solutions like a small VPS.
That said, the single-server approach is a bit unwieldy when it comes to scaling your site for higher loads. As with other approaches, you can begin scaling the single-server setup vertically by purchasing a more powerful VPS or server, but trouble starts to sneak in when it is no longer cost-effective to increase capacity by upgrading your machine.
Upon reaching that situation, your first move will typically be to move your database to a second machine, which is easily accomplished. However, when you need to add more capacity for serving dynamic or static content, the setup is a bit inflexible. Your first and only option is to add additional machines behind a load-balancer.
Load balancing and scaling for single http server approach.
Although in reality you'd likely have Postgres on a separate machine.
In review, the single-server setup may be the most efficient option for low resource environments, is relatively simple to configure1, but must serve static and dynamic content with the same configuration, and thus may open itself up for inefficiencies as demands grow (we'll discuss this more below).

The Multi-Server Approach

Anyone who has read a tutorial describing mod_python usage has probably read the term fat threads, which is the word du jour for describing Apache worker threads whenmod_python is enabled. This is because each mod_python worker thread needs a Python interpreter associated with it, causing each worker thread to consume approximately 20 megs of ram.
There are good reasons for that, and mod_python is extremely fast at serving dynamic requests, so the cost is certainly justifiable. However, why have a heavy thread serve a static file when a much lighter one is sufficient? Further, how do we prevent our relatively low quantity of heavy threads from being monopolized by slow connections (and as a result able to serve fewer concurrent users)?
The standard answer to that question is to have a lightweight server that is the first point of content for users, serves static media, and proxies requests for dynamic media to heavier threads on a second server.
Image of nginx, apache2, mod_wsgi, postgres, virtual env, memcached deployment.
Essentially the argument being made be the multi-server setup is that specialization leads to efficiency. By allowing one server to focus only on serving dynamic media we can tweak its settings to maximize performance for that task. By allowing a second server to focus on serving static media, we can optimize it as well.
Beyond the specialization leads to optimization argument, the multi-server approach has another benefit over the single-server approach: ease of efficient scaling. Because we have separated the concerns from one another, it makes it very easy to scale efficiently by adding capacity exactly where it is needed.
With only minimal configuration file changes you could switch the simple one machine model to a many machine model. This is especially simple if the narrowest point in your pipe is serving dynamic content.
Image of splitting a one machine setup to multiple machines.
Admittedly this system does ask Nginx to perform as both a proxy and the static media server, and if serving static media requires more throughput than one machine can provide, you'll need to move to the server pool approach (which finalizes the separation of concerns).
Image of load-balanced setup for Django.
To a certain extent it's much easier to scale vertically (purchase a larger VPS or server) than to scale horizontally, and that should always be the first choice. However, should you reach a point where scaling vertically ceases to be cost-effective, the multi-server approach provides a tremendous amount of flexibility and allows higher gains per server due to specialization.
In the end, there isn't a right-wrong choice between using the single-server or the multi-server approach. While the multi-server approach will eventually out-perform the single-server approach, with limited resources may underperform it.
That said, my experience with the multi-server approach has been very positive, even with very limited resources (256 megabytes of RAM on a VPS), so--if you're willing to do some extra configuration--I'd personally recommend going with multi-server from the start.

Introduction to Architecting Systems for Scale


Few computer science or software development programs attempt to teach the building blocks of scalable systems. Instead, system architecture is usually picked up on the job by working through the pain of a growing product or by working with engineers who have already learned through that suffering process.
In this post I'll attempt to document some of the scalability architecture lessons I've learned while working on systems at Yahoo! and Digg.
I've attempted to maintain a color convention for diagrams in this post:
  • green represents an external request from an external client (an HTTP request from a browser, etc),
  • blue represents your code running in some container (a Django app running on mod_wsgi, a Python script listening to RabbitMQ, etc), and
  • red represents a piece of infrastructure (MySQL, Redis, RabbitMQ, etc).

Load Balancing: Scalability & Redundancy

The ideal system increases capacity linearly with adding hardware. In such a system, if you have one machine and add another, your capacity would double. If you had three and you add another, your capacity would increase by 33%. Let's call this horizontal scalability.
On the failure side, an ideal system isn't disrupted by the loss of a server. Losing a server should simply decrease system capacity by the same amount it increased overall capacity when it was added. Let's call this redundancy.
Both horizontal scalability and redundancy are usually achieved via load balancing.
(This article won't address vertical scalability, as it is usually an undesirable property for a large system, as there is inevitably a point where it becomes cheaper to add capacity in the form on additional machines rather than additional resources of one machine, and redundancy and vertical scaling can be at odds with one-another.)
Load Balancing
Load balancing is the process of spreading requests across multiple resources according to some metric (random, round-robin, random with weighting for machine capacity, etc) and their current status (available for requests, not responding, elevated error rate, etc).
Load needs to be balanced between user requests and your web servers, but must also be balanced at every stage to achieve full scalability and redundancy for your system. A moderately large system may balance load at three layers: from the
  • user to your web servers, from your
  • web servers to an internal platform layer, and from your
  • internal platform layer to your database.
There are a number of ways to implement load balancing in your setup.

Smart Clients

Adding load-balancing functionality into your database (cache, service, etc) client is usually an attractive solution for the developer. Is it attractive because it is the simplest solution? Usually, no. Is it seductive because it is the most robust? Sadly, no. Is it alluring because it'll be easy to reuse? Tragically, no.
Developers lean towards smart clients because they are developers, and so they are used to writing software to solve their problems, and smart clients are software.
With that caveat in mind, what is a smart client? It is a client which takes a pool of service hosts and balances load across them, detects downed hosts and avoids sending requests their way (they also have to detect recovered hosts, deal with adding new hosts, etc, making them fun to get working decently and a terror to get working correctly).

Hardware Load Balancers

The most expensive--but very high performance--solution to load balancing is to buy a dedicated hardware load balancer (something like a Citrix NetScaler). While they can solve a remarkable range of problems, hardware solutions are remarkably expensive, and they are also "non-trivial" to configure.
As such, generally even large companies with substantial budgets will often avoid using dedicated hardware for all their load-balancing needs; instead they use them only as the first point of contact from user requests to their infrastructure, and use other mechanisms (smart clients or the hybrid approach discussed in the next section) for load-balancing for traffic within their network.

Software Load Balancers

If you want to avoid the pain of creating a smart client, and purchasing dedicated hardware is excessive, then the universe has been kind enough to provide a hybrid approach: software load-balancers.
HAProxy is a great example of this approach. It runs locally on each of your boxes, and each service you want to load-balance has a locally bound port. For example, you might have your platform machines accessible via localhost:9000, your database read-pool at localhost:9001 and your database write-pool at localhost:9002. HAProxy manages healthchecks and will remove and return machines to those pools according to your configuration, as well as balancing across all the machines in those pools as well.
For most systems, I'd recommend starting with a software load balancer and moving to smart clients or hardware load balancing only with deliberate need.

Caching

Load balancing helps you scale horizontally across an ever-increasing number of servers, but caching will enable you to make vastly better use of the resources you already have, as well as making otherwise unattainable product requirements feasible.
Caching consists of: precalculating results (e.g. the number of visits from each referring domain for the previous day), pre-generating expensive indexes (e.g. suggested stories based on a user's click history), and storing copies of frequently accessed data in a faster backend (e.g.Memcache instead of PostgreSQL.
In practice, caching is important earlier in the development process than load-balancing, and starting with a consistent caching strategy will save you time later on. It also ensures you don't optimize access patterns which can't be replicated with your caching mechanism or access patterns where performance becomes unimportant after the addition of caching (I've found that many heavily optimized Cassandraapplications are a challenge to cleanly add caching to if/when the database's caching strategy can't be applied to your access patterns, as the datamodel is generally inconsistent between the Cassandra and your cache).

Application Versus Database Caching

There are two primary approaches to caching: application caching and database caching (most systems rely heavily on both).
Application Cache
Application caching requires explicit integration in the application code itself. Usually it will check if a value is in the cache; if not, retrieve the value from the database; then write that value into the cache (this value is especially common if you are using a cache which observes the least recently used caching algorithm). The code typically looks like (specifically this is a read-through cache, as it reads the value from the database into the cache if it is missing from the cache):
key = "user.%s" % user_id
user_blob = memcache.get(key)
if user_blob is None:
    user = mysql.query("SELECT * FROM users WHERE user_id=\"%s\"", user_id)
    if user:
        memcache.set(key, json.dumps(user))
    return user
else:
    return json.loads(user_blob)
The other side of the coin is database caching.
Database Cache
When you flip your database on, you're going to get some level of default configuration which will provide some degree of caching and performance. Those initial settings will be optimized for a generic usecase, and by tweaking them to your system's access patterns you can generally squeeze a great deal of performance improvement.
The beauty of database caching is that your application code gets faster "for free", and a talented DBA or operational engineer can uncover quite a bit of performance without your code changing a whit (my colleague Rob Coli spent some time recently optimizing our configuration for Cassandra row caches, and was succcessful to the extent that he spent a week harassing us with graphs showing the I/O load dropping dramatically and request latencies improving substantially as well).

In Memory Caches

The most potent--in terms of raw performance--caches you'll encounter are those which store their entire set of data in memory. Memcached and Redis are both examples of in-memory caches (caveat: Redis can be configured to store some data to disk). This is because accesses to RAM are orders of magnitude faster than those to disk.
On the other hand, you'll generally have far less RAM available than disk space, so you'll need a strategy for only keeping the hot subset of your data in your memory cache. The most straightforward strategy is least recently used, and is employed by Memcache (and Redis as of 2.2 can be configured to employ it as well). LRU works by evicting less commonly used data in preference of more frequently used data, and is almost always an appropriate caching strategy.

Content Distribution Networks

A particular kind of cache (some might argue with this usage of the term, but I find it fitting) which comes into play for sites serving large amounts of static media is thecontent distribution network.
Content Distribution Network
CDNs take the burden of serving static media off of your application servers (which are typically optimzed for serving dynamic pages rather than static media), and provide geographic distribution. Overall, your static assets will load more quickly and with less strain on your servers (but a new strain of business expense).
In a typical CDN setup, a request will first ask your CDN for a piece of static media, the CDN will serve that content if it has it locally available (HTTP headers are used for configuring how the CDN caches a given piece of content). If it isn't available, the CDN will query your servers for the file and then cache it locally and serve it to the requesting user (in this configuration they are acting as a read-through cache).
If your site isn't yet large enough to merit its own CDN, you can ease a future transition by serving your static media off a separate subdomain (e.g. static.example.com) using a lightweight HTTP server like Nginx, and cutover the DNS from your servers to a CDN at a later date.

Cache Invalidation

While caching is fantastic, it does require you to maintain consistency between your caches and the source of truth (i.e. your database), at risk of truly bizarre applicaiton behavior.
Solving this problem is known as cache invalidation.
If you're dealing with a single datacenter, it tends to be a straightforward problem, but it's easy to introduce errors if you have multiple codepaths writing to your database and cache (which is almost always going to happen if you don't go into writing the application with a caching strategy already in mind). At a high level, the solution is: each time a value changes, write the new value into the cache (this is called a write-through cache) or simply delete the current value from the cache and allow a read-through cache to populate it later (choosing between read and write through caches depends on your application's details, but generally I prefer write-through caches as they reduce likelihood of a stampede on your backend database).
Invalidation becomes meaningfully more challenging for scenarios involving fuzzy queries (e.g if you are trying to add application level caching in-front of a full-text search engine like SOLR), or modifications to unknown number of elements (e.g. deleting all objects created more than a week ago).
In those scenarios you have to consider relying fully on database caching, adding aggressive expirations to the cached data, or reworking your application's logic to avoid the issue (e.g. instead of DELETE FROM a WHERE..., retrieve all the items which match the criteria, invalidate the corresponding cache rows and then delete the rows by their primary key explicitly).

Off-Line Processing

As a system grows more complex, it is almost always necessary to perform processing which can't be performed in-line with a client's request either because it is creates unacceptable latency (e.g. you want to want to propagate a user's action across a social graph) or it because it needs to occur periodically (e.g. want to create daily rollups of analytics).

Message Queues

For processing you'd like to perform inline with a request but is too slow, the easiest solution is to create a message queue (for example, RabbitMQ). Message queues allow your web applications to quickly publish messages to the queue, and have other consumers processes perform the processing outside the scope and timeline of the client request.
Dividing work between off-line work handled by a consumer and in-line work done by the web application depends entirely on the interface you are exposing to your users. Generally you'll either:
  1. perform almost no work in the consumer (merely scheduling a task) and inform your user that the task will occur offline, usually with a polling mechanism to update the interface once the task is complete (for example, provisioning a new VM on Slicehost follows this pattern), or
  2. perform enough work in-line to make it appear to the user that the task has completed, and tie up hanging ends afterwards (posting a message on Twitter or Facebook likely follow this pattern by updating the tweet/message in your timeline but updating your followers' timelines out of band; it's simple isn't feasible to update all the followers for aScobleizer in real-time).
Message Queue
Message queues have another benefit, which is that they allow you to create a separate machine pool for performing off-line processing rather than burdening your web application servers. This allows you to target increases in resources to your current performance or throughput bottleneck rather than uniformly increasing resources across the bottleneck and non-bottleneck systems.

Scheduling Periodic Tasks

Almost all large systems require daily or hourly tasks, but unfortunately this seems to still be a problem waiting for a widely accepted solution which easily supports redundancy. In the meantime you're probably still stuck with cron, but you could use the cronjobs to publish messages to a consumer, which would mean that the cron machine is only responsible for scheduling rather than needing to perform all the processing.
Does anyone know of recognized tools which solve this problem? I've seen many homebrew systems, but nothing clean and reusable. Sure, you can store the cronjobs in aPuppet config for a machine, which makes recovering from losing that machine easy, but it would still require a manual recovery, which is probably acceptable but not quite perfect.

Map-Reduce

If your large scale application is dealing with a large quantity of data, at some point you're likely to add support for map-reduce, probably using Hadoop, and maybe Hive orHBase.
Map Reduce
Adding a map-reduce layer makes it possible to perform data and/or processing intensive operations in a reasonable amount of time. You might use it for calculating suggested users in a social graph, or for generating analytics reports.
For sufficiently small systems you can often get away with adhoc queries on a SQL database, but that approach may not scale up trivially once the quantity of data stored or write-load requires sharding your database, and will usually require dedicated slaves for the purpose of performing these queries (at which point, maybe you'd rather use a system designed for analyzing large quantities of data, rather than fighting your database).

Platform Layer

Most applications start out with a web application communicating directly with a database. This approach tends to be sufficient for most applications, but there are some compelling reasons for adding a platform layer, such that your web applications communicate with a platform layer which in turn communicates with your databases.
Platform Layer
First, separating the platform and web application allow you to scale the pieces independently. If you add a new API, you can add platform servers without adding unnecessary capacity for your web application tier. (Generally, specializing your servers' role opens up an additional level of configuration optimization which isn't available for general purpose machines; your database machine will usually have a high I/O load and will benefit from a solid-state drive, but your well-configured application server probably isn't reading from disk at all during normal operation, but might benefit from more CPU.)
Second, adding a platform layer can be a way to reuse your infrastructure for multiple products or interfaces (a web application, an API, an iPhone app, etc) without writing too much redundant boilerplate code for dealing with caches, databases, etc.
Third, a sometimes underappreciated aspect of platform layers is that they make it easier to scale an organization. At their best, a platform exposes a crisp product-agnostic interface which masks implementation details. If done well, this allows multiple independent teams to develop utilizing the platform's capabilities, as well as another team implementing/optimizing the platform itself.