Web Services

Platform Architecture in Computer Science: Caching and File Storage

One of the important aspect of any platform is performance, to increase the performance to satisfy end users with quick access one can not escape from in memory cache. Database operations are always costly, executing complex queries to meet real time needs will make the entire platform slow. For faster access, in-memory cache is very much needed. People use Radis and Kafka.

Before reading further I recommend reading my previous article on platform architecture

Caching in platform Architecture

Now interesting question is where do Caching service fits in my architecture? How do we represent it in platform architecture and where do we integrate caching?

Typically we should have a cache manager within the app which manages caching and database. For any request first we have to check whether required data is in cache ? if not then only hit Database else return from cache.

In case of data update or new insertions , the cache manager has to take care of updating the cache and then make the updated data available for further read operations.

The updated platform architecture looks as follows now

Platform architecture with caching

Redis or Kafka are well known services for in-memory cache, but both have their own purpose, so we have to decide upon what to use when ?

Read more about Redis

File Server for file storage in platform architecture

I thought of covering this also in the same article as it is a small but very important to consider. Because lot of developers have confusion regarding where to store files ? many people will create a folder in their application server and store all files there itself, which is a very wrong for ay real-time applications.

It is recommended to store files in file servers like Amazon AWS S3 bucket and Google Storage, if its publicly sharable multimedia file like image or video then go for Cloudinary kind of CDN services.

Why not to store files in application server?

  1. Application servers like amazon EC2 or Google App engine are not made for file storage, their purpose is to run your app
  2. Application servers are compute engines where you can install any software whichever you need for you app to run in cloud, where as file servers are just providing the storage to store huge files
  3. File servers have different qualities altogether they can take you files backup, create replica if needed, they are capable to transfer huge data fast enough, they are cheaper than app servers
  4. in case of app servers, for some reason if something goes wrong, u may need to create new server quickly and release your app again, if your all file data is also stored in the same server you may loose it permanently, but file server are more reliable for that matter
  5. This is what amazon claims -> Amazon S3 is designed for 99.999999999% (11 9’s) of data durability because it automatically creates and stores copies of all S3 objects across multiple systems.
  6. File servers also provide other services like securing files through authorised access, encrypt the files
  7. Manage and access control – you can create multiple folders and access each folder for specific service so that other services won’t get access to it
  8. File servers like Amazon S3 provide services like querying on the data stored in files, all such nice features you won’t get it in app servers because they are not meant for it

Platform Architecture in Computer Science: Case Study on Various Platforms

Before reading this article, I strongly recommend reading my previous two articles.

Platform Architecture with Multiple Apps Approach

Platform Architecture with Micro-Service Approach

Despite all of these inputs, I am still saying platform architecture depends upon various needs of the platform, hence there is nothing like one standard way, it will be always evolving. Hence let us look into some of the references for Highly Scalable Platform Architectures to understand even better

  1. Linked in Architecture – Reference – Click Here

Observe here, a separate replica set for Database ?

  1. Uber Architecture – Reference Click Here

Uber has a micro-service architecture.

  1. Netflix Architecture – Reference Click Here

Netflix architecture looks very complex and it is micro-service architecture

Some highlights of Netflix Architecture, Hundred’s of microservices and one giant service. thousand’s of servers spread across the world, thousand’s of Content Delivery Networks, Netflix uses their own CDN called Open Connect

  1. 100s of microservices
  2. 1000s of daily production changes
  3. 10,000s of instances running in AWS cloud
  4. 10, 000, 000, 000 hours of streamed

This is how it looks 🙂

Reference: How Netflix works: the (hugely simplified) complex stuff that happens every time you hit Play

  1. Ebay Architecture

Read More on Platform Architecture

Thank You

Platform Architecture in Computer Science: With Multiple Apps Approach

There are many ways to design the platform architecture, however every platform has its own unique requirements. The architecture of every platform can vary totally to meet the needs of respective platform.

There are many case studies to look into platform architecture which I will cover in different article, we can look into linked-in, ebay, Amazon and netflix architectures to get better understanding on Platform architecture.

For now in this article we will understand first approach that Having Multiple Apps with its own independent Database and Backend. For our understanding purpose we will consider designing a platform for an Amazon Kind of Online Shopping Platform

Read Basics of Platform Architecture before further reading

Platform Architecture for Amazon Kind of Online Shopping Platform with Multiple Apps Approach

If you consider Amazon kind of Online Shopping Platform, we first have to identify which are the different huge modules which are candidates for making it as a separate app altogether

  1. Sellers or Vendors who sell the products
    1. Seller is the one who has his shop and sell products in amazon
    2. He should be able to add his products
    3. He should be able to manage discounts, offers for his products
    4. He should be able to dispatch his product
    5. He should be able to manage his revenue/profit and other finance aspects
  2. Buyers
    1. The one who buy products in Amazon
    2. He should be able to manage his Cart
    3. He should be able to manage his delivery addresses
    4. He should be able to do payment using his choice of payment mode
  3. Product Dispatch Management
    1. Tracking the product while dispatching from one place to another
    2. Every city has a collection centers and products has to be managed for timely delivery
  4. Products Delivery Management
    1. Once product is reached the destination city it has to be picked by delivery person
    2. Assign delivery person
    3. Deliver to customer and update the status
    4. receive cash in case is Cash-On-Delivery
  5. Amazon Finance Management
    1. This is kind of Super Admin Functionality
    2. Managing refunds
    3. managing failed transactions
    4. Transferring money to Seller

I listed only few functionalities however there will be many more under each of these main features.

Why Can’t be its one super big Monolithic Application ? Rather than multiple Apps ?

To answer this question we have to think of following important aspects which we covered in our first Article Which are as follows

  1. Scalability : For Amazon Kind of Applications, millions of requests will be coming every second. There are millions of users buying and millions of sellers selling and millions of products listed, millions of transactions happening. It is highly impossible to handle everything in one huge monolithic server, because every server has some upper limits with respect to hardware and capacity, one huge database to scale it to that level we have to divide it into multiple pieces and manage it independently.
  2. Maintainability: It is very hard to maintain one huge monolithic app for such a huge volume.
  3. Resilient: Any major update to particular part of the platform should not affect to other parts of the platform
  4. Development: For amazon kind of huge platforms, they have huge team spread across the world and each teach is enhancing their own module by doing lot of research within their small team. It is not possible to manage development activity effectively if its one huge monolithic app

Now let us see how the Architecture Diagram looks: You can use various apps for designing Architecture Diagram

In the above diagram, each app is one server and it has its own database. There are third party services used commonly across many apps, like

  1. Elastic Search Service : For faster product search, Elastic Database is must for better searching capability.
  2. Cloudinary is another service used for multi media file handling
  3. Authentication service is like firebase, auth0 for user authentication
  4. Many more such services will be used

Advantages of Multi Application Platform Architecture

Scalability: In this architecture the platform is scalable to handle high traffic, because during peak time like Amazon big billion day, more and more people will buy products, the traffic will be too high for Consumer App. So in that case if its independent server by itself, we can increase the capacity of that server alone to handle millions of requests, however other apps may not need so much so at this stage.

Continue Reading : Where API Gateway and GraphQL Fit in Platform Architecture

Platform Architecture in Computer Science: Different approaches and Benefits

What is Platform Architecture in Computer Science

A platform architecture is an abstract high level design of the platform that answers to some of the key important factors of any platform like scalability, resilience, maintainability. It should cover almost all important big modules, multiple apps, all the servers, databases, caching, third party solutions and etc.

A platform should be ever evolvable, should be able to adopt to the new changes and needs of the platform and it helps to meet all technical and operational requirements with focus on optimising performance and security.

Desirable Properties of Platform Architecture

  1. High level of Abstraction – It should be simple enough and comprehensive enough to get high level of understanding
  2. Resilient – Each major module (app) should not be get affected so much due to one defective app
  3. Scalable – Architecture should consider the scalability of the platform “Scalability” refers to the number of users, sessions, transactions, and operations that can be accommodated by the entire system
  4. Maintainable – Should be able to make changes to any part of the system without breaking or damaging too much to other parts
  5. Ever Enhancing – it should be able to evolve every-time when there is a need of change

Important Aspects to focus on while designing platform architecture.

  1. How many servers we need to maintain, is it per app level or every major functionality
  2. How caching is handled in platform
  3. API Gateways for API security, metering, throttling
  4. Searching functionality within the platform
  5. Users and Identity Management
  6. Security
  7. Databases
  8. File Servers
  9. Third Party Services if any
  10. Data query and Manipulation for faster data access like using GraphQL
  11. Communication between each apps or each servers using event queue, event bus or intermediate app whichever way it is
  12. Handling batch processes using cronjobs or cloud functions
  13. Data mining, AI System

For Different Approaches for designing Platform Architectures click here

Caused by: java.lang.ClassNotFoundException: org.hibernate.cache.EntityRegion

Caused by: java.lang.ClassNotFoundException: org.hibernate.cache.EntityRegion

Caused by: java.lang.ClassNotFoundException: org.hibernate.cache.EntityRegion

OR

Caused by: org.hibernate.cache.NoCacheRegionFactoryAvailableException: Second-level cache is used in the application, but property hibernate.cache.region.factory_class is not given; please either disable second level cache or set correct region factory using the hibernate.cache.region.factory_class setting and make sure the second level cache provider (hibernate-infinispan, e.g.) is available on the classpath.

 

Solution

  1.  Replace POM dependency for net.sf.ehcache : ehcache-core

  Replace below lines

                
		dependency
			net.sf.ehcache
			ehcache-core
			2.6.11
		/dependency
		

From below lines

		
		dependency
			org.hibernate
			hibernate-ehcache
			4.3.5.Final
		/dependency
		

2. set Factory_class in spring.xml file as given below

Replace below lines

				prop key="hibernate.cache.region.factory_class" net.sf.ehcache.hibernate.EhCacheRegionFactory/prop
				prop key="hibernate.cache.use_query_cache"> true/prop

With below lines

				prop key="hibernate.cache.region.factory_class"> org.hibernate.cache.ehcache.EhCacheRegionFactory /prop
				prop key="hibernate.cache.use_query_cache">true /prop

3.  Then use setCacheable(true); for your queries in hibernate criteria

 

Selecting certain fields in Hibernate Criteria using Projections

Selecting certain fields in Hibernate Criteria using Projections

This is not a great post but many people will face this issue and the solution is very simple for which many will spend hours of time to find it.

Issue faced by many are selecting certain fields of the table using hibernate criteria, converting array of Objects (Object[]) to respective custom class object, Even after converting the values for the fields will be set to default rather than actual values of the fields.

Take an example :

  Class Person {
    private Integer personid;
    private String personname;
    private String mobilenumber;
    private String permanentaddress;
    private String localaddress;

    public Integer getPersonid(){ }

    public void setPersonid(Integer personid){ }

    public String getPersonname(){ }

    public void setPersonname(String personname){ }

    //Other fields getter/Setter
    
  }

In this example assume that you wish to fetch only personid and personname using hibernate criteria

Fetching only selected fields using Hibernate Criteria







  List persons = null;
  Criteria criteria = sessionObject.createCriteria(Person.class);
		 criteria.setProjection(Projections.projectionList().add(Projections.property("personid")).add(Projections.property("personname")));

 criteria.setResultTransformer(Transformers.aliasToBean(Person.class));
 persons = criteria.list();

Issue : All fields are getting empty/default values after using hibernate projections

This issue is a very difficult to tackle, because hibernate doesn’t through any exception for this but it returns objects filled with default values of fields.

Solution: The solutions is really simple, just use an alias to each field in projections

//See alias personid and personname for both the fields
//Projections.property(“personid”),”personid”) and Projections.property(“personname”),”personname”)

 criteria.setProjection(Projections.projectionList().add(Projections.property("personid"),"personid").add( Projections.property("personname"),"personname"));

 

The above solution doesn’t work for One-To-Many relationship also when there is an aggregation, has-a relationship.

A Wrapper to fetch selected fields using hibernate Projections for One-To-Many relationship

Download the library given below and import it in your project, then define a Response Class like PersonResponse.java, which should be exact replica of Person.java , where it holds all details of a person fetched from database person table.

then just use the below code 

personCriteria.setResultTransformer(new AliasToBeanNestedResultTransformer(PersonResponse.class));

Source Code : AliasToBeanNestedResultTransformer

Thanks to : http://stackoverflow.com/a/25770708/526438

Server Sent Events (SSE) using Jersey, spring and Javascript

Server Side Event not firing in Jersey 2.8 using SSE

Notifications were playing a major role in every applications either it is a mobile application or web application or even a desktop application. These days every latest Operating system updates were including Facebook as a service within OS itself and mail notifications were just on your desktop.

It is important to learn how to support realtime notifications in your web applications. Following technologies were considered in the given example

Springs

Jersey2.8

Javascript

Server Sent Events Javascript Code

Register to Server Sent Events in Javascript

 

var notificationBaseURL =  "http://myapplication.com/"; //The URL Where your services are hosted
function listenAllEvents() {
	if (typeof (EventSource) !== "undefined") {

		var source = new EventSource(
				notificationBaseURL+"applicationnotifier/sse/events/register/"+loggedInUserName);
		source.onmessage = notifyEvent;
	} else {
		console.log("Sorry no event data sent - ");
	}
}

function notifyEvent(event) {
	var responseJson = JSON.parse(event.data);
	alert("... Notification Received ...");
}

In the above code the URL is specific to user who have logged in. Every user has to register for notification.

Java Spring Code For Server Sent Events(SSE):

 

//    NotificationHandler.java

package com.applicationnotifier.Notification.WebServices.Impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Singleton;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jettison.json.JSONObject;
import org.glassfish.jersey.media.sse.EventOutput;
import org.glassfish.jersey.media.sse.OutboundEvent;
import org.glassfish.jersey.media.sse.SseBroadcaster;
import org.glassfish.jersey.media.sse.SseFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.ResponseBody;

import com.applicationnotifier.Notification.framework.impl.NotificationFrameworkFactory;
import com.applicationnotifier.Notification.framework.intf.NotificationFrameworkInterface;
import com.applicationnotifier.dao.notification.NotificationDao;
import com.applicationnotifier.pojo.Form;
import com.applicationnotifier.pojo.notification.Notification;
import com.applicationnotifier.responsepojo.NotificationResponse;

/*
    A CLASS THAT REGISTERS NOTIFICATIONS
    Registering does following functions
    1. Create a broadcaster object for each notification type
    2. Map Event Output object for each broadcaster to broadcast a message
    3. Broadcast the event
 */

@Singleton
@Path("/events")
public class NotificationHandler {
	
	final static Logger logger = LoggerFactory.getLogger(NotificationHandler.class);
	@Autowired
	@Qualifier("notificationDaoImpl")
	NotificationDao notificationDao;

    /*
        A map thats keeps track of each notification and its output event object. broadcaster object.
        SseBroadcaster will perform broadcasting the notification
     */
	Map<String, SseBroadcaster> notificationBroadcasterMap = new HashMap<String, SseBroadcaster>();

    
    /*
     registerForAnEventSummary: will be called when the client registers for notifications
     in javascript we call listenAllEvents() method.
     */
	@Path("/register/{userName}")
	@Produces(SseFeature.SERVER_SENT_EVENTS)
	@GET
	public @ResponseBody EventOutput registerForAnEventSummary(
			@PathParam("userName") String userName) {
		try {
			NotificationFrameworkFactory factory = new NotificationFrameworkFactory();
			
			EventOutput eventOutput = new EventOutput();
			

            /* Returns all types of notifications, for each type of notification there should be an implementation as newMessageNotificationImplementation or newMessageNotificationFramework
             
                Exmple  newMessageNotification, in this example this notification has a class
                newMessageNotificationFramework.java
             
             */
			List notificationTypes = getAllNotificationTypes();

			for (String notificationType : notificationTypes) {
				NotificationFrameworkInterface notificationInterface = factory
						.getNotifieir(notificationType);
				String keyVal = getKeyVal(notificationType, userName);
				if (!notificationBroadcasterMap.containsKey(keyVal)) {
                    //Add broadcaster to map
					notificationBroadcasterMap.put(keyVal,
							notificationInterface.getBroadcaster());
				}
				
                //Get broadcaster and add event output
				notificationBroadcasterMap.get(keyVal).add(eventOutput);
			}

			return eventOutput;
		} catch (NullPointerException exception) {
			logger.error("Exception Occurred: ", exception);
		}
		return null;
	}

    /*
     getKeyVal : every user must register for each notification
                Notification Key : newMessageNotification_Ram indicates Ram is listening to newMessage notification
     */
	private String getKeyVal(String typeOfEvent, String userName) {

		switch (typeOfEvent) {
		case "newMessageNotification":
        case "likeNotification":
        case "commentNotification":
			return typeOfEvent + "_" + userName;
        		
		default:
			return null;
		}
	}

    //Return different types of notifications supported in your application
	private List getAllNotificationTypes() {
		List notificationTypes = new ArrayList();
		notificationTypes.add("newMessageNotification");
		notificationTypes.add("likeNotification");
		notificationTypes.add("commentNotification");
		return notificationTypes;
	}

    /*
        Just returns a Map object for a given json string
     */
	@SuppressWarnings("unchecked")
	protected HashMap<String, String> getMapFromJson(String message) {
		ObjectMapper mapper = new ObjectMapper();
		HashMap<String, String> value = null;
		try {
			value = mapper.readValue(message, HashMap.class);
		} catch (IOException e) {
			logger.error("Exception Occurred: ", e);
		}
		return value;
	}

    /*
        Broad cast notification to all clients which are registered for notification
     */
	@Path("/broadcast")
	@POST
	@Produces(MediaType.TEXT_PLAIN)
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public String broadcastNotifications(@FormParam("message") String message) {

		try {
			HashMap<String, String> value = getMapFromJson(message);
			JSONObject responseJson = new JSONObject(value);
			/*
			 * System.out .println("received data: " + message);
			 */
			OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
			OutboundEvent event = eventBuilder.name("message")
					.mediaType(MediaType.TEXT_PLAIN_TYPE)
					.data(String.class, responseJson.toString()).build();

            //Things you wish to send to client
			String keyVal = getKeyVal(value.get("ntftyp"),
                                      , value.get("un"));
			System.out.println("broadcasting: " + message + " to: " + keyVal);
			if (notificationBroadcasterMap.get(keyVal) != null) {
				// System.out.println("message is ready for broadcasting");
				notificationBroadcasterMap.get(keyVal).broadcast(event);
			} else
				System.out.println("no broadcaster for: " + keyVal);
		} catch (NullPointerException exception) {
			logger.error("Exception Occurred: ", exception);
		}

		return "Message '" + message + "' has been broadcast.";
	}
}



// NewMessageNotificationBusniessIntf.java

package com.applicationnotifier.Notification.business.intf;

import java.util.HashMap;
import java.util.Map;

import com.applicationnotifier.Notification.framework.impl.NotificationAbstractFramework;

public abstract class NewMessageNotificationBusniessIntf extends NotificationAbstractFramework {
    public boolean notifyNewMessage(HashMap<String, Object> message);
}


// NewMessageNotificationBusniessImpl.java
package com.applicationnotifier.Notification.business.impl;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.applicationnotifier.Notification.business.intf.NewMessageNotificationBusniessIntf;

/*
    Call these methods when some updates happened in your Database
    Example - Some one sent a message, the messageInsert service will be called (Spring Controller,Service,Repository ) 
    in Service layer create object of NewMessageNotificationBusniessImpl and call these methods to notify
 
    In these methods just call Post/Get methods , these methods are services for your notifications
        URL - sse/events/broadcast/
 
    Any call to sse/events/broadcast/ will call a method defined in NotificationHandler class i.e broadcastNotifications
 */
@Service
public class NewMessageNotificationBusniessImpl extends
		NewMessageNotificationBusniessIntf {
	
    @Override
	public boolean notifyNewMessage(HashMap<String, Object> message) {
		try {
			message.put("msg", message.get("un") + " You have new message ");
			HttpClient httpClient = new HttpClient();

			PostMethod postMethod = null;
            postMethod = new PostMethod(
                    resourceBundle.getString("localhost:8080")
                            + resourceBundle.getString("applicationnotifier")
                            + resourceBundle
                                    .getString("sse/events/broadcast/"));
			
			// postMethod.addParameter(data[0]);
			NameValuePair[] parametersBody = {
					new NameValuePair("message", convertToJson(message)),
					};
			postMethod.setRequestBody(parametersBody);
			httpClient.executeMethod(postMethod);

			BufferedReader responseReader = new BufferedReader(
					new InputStreamReader(postMethod.getResponseBodyAsStream()));
			String line;
			while ((line = responseReader.readLine()) != null) {
				System.out.println(line);
			}
						
			return true;
		} catch (Exception e) {
			logger.error("Exception Occurred: ", e);
		}
		return false;
	}
}


//NotificationAbstractFramework.java
package com.applicationnotifier.Notification.framework.impl;

import java.io.IOException;
import java.util.Map;

import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class NotificationAbstractFramework {
	
	final static Logger logger = LoggerFactory.getLogger(NotificationAbstractFramework.class);

	protected String convertToJson(Map<String, Object> message) {
		try {
			ObjectMapper mapper = new ObjectMapper();
			return mapper.writeValueAsString(message);
		} catch (IOException e) {
			logger.error("Exception Occurred: ", e);
		}
		return "";
	}
}



Web Services – Chapter 2

RESTFul Web Services – A First Step

Before starting with RESTFul web services , one must be knowing the basics of web services, We have studied basics of web services in our previous chapter, Once you learn basics, it will be great to go ahead.

As we discussed in previous chapter Web services plays a major role in future of web. We will try to learn how the things will be developed, we will have a hands on with development of web services using java. Before starting with web service development we will like to give step-by-step guide for java setup.

We need java sdk installed, tomcat server installed and eclipse as an IDE for development. Web services can be developed with PHP, C# .net , Ruby on Rails. Since our team is comfortable with java, we would like to write further chapters targeting java for the same.

Set-up for Mac Users
Install Java sdk
1> Download jdk 7 from the link

2> Double click on .dmg file , which opens a window and double click on package file as shown in the fig below.

jdk dmg img

3> Click continue in the installation window

4> Enter user name and password of your system

Install tomcat
1> Download tomcat from the link
(Download the zipped file – zip (pgp, md5) )

2> Unarchive the tomcat folder from your download folder.

3> Open the terminal and execute the following commands

These commands are used just to move the tomcat folder into /user/local folder.

sudo mkdir -p /usr/local

sudo mv ~//apache-tomcat-7.0.47 /usr/local

(Usually it will be sudo mv ~/Downloads/apache-tomcat-7.0.47 /usr/local)

4> Create symbolic link for the tomcat – this helps to keep tomcat updated when we get latest tomcat updates.
First create tomcat folder
sudo rm -f /Library/Tomcat

Create symbolic link of tomcat
sudo ln -s /usr/local/apache-tomcat-7.0.47 /Library/Tomcat

5> To make tomcat executable, the ownership of the folder must be changed
sudo chown -R <your_username> /Library/Tomcat

6> To start and stop tomcat we need to run the scripts, to set the execute permission to scripts run the below command

The installation of tomcat is done!
Check whether tomcat starts smoothly or not by starting tomcat with the script
Screen Shot 2014-06-04 at 8.50.01 pm
knowledgecess:~ cess$ /Library/Tomcat/bin/startup.sh

Using CATALINA_BASE: /Library/Tomcat
Using CATALINA_HOME: /Library/Tomcat
Using CATALINA_TMPDIR: /Library/Tomcat/temp
Using JRE_HOME: /Library/Java/Home
Using CLASSPATH: /Library/Tomcat/bin/bootstrap.jar:/Library/Tomcat/bin/tomcat-juli.jar

knowledgecess:~ cess$ /Library/Tomcat/bin/shutdown.sh
Using CATALINA_BASE: /Library/Tomcat
Using CATALINA_HOME: /Library/Tomcat
Using CATALINA_TMPDIR: /Library/Tomcat/temp
Using JRE_HOME: /Library/Java/Home
Using CLASSPATH:
/Library/Tomcat/bin/bootstrap.jar:/Library/Tomcat/bin/tomcat-juli.jar
knowledgecess:~ cess$

In our next chapter let us try to create a sample on web services in Java.