private synchronized Message dispatch(Message m) {
		Message ret = null;
		String method = m.getContent();
		switch (method) {
		// message from client
		case "start":
			Job job = ((JobMessage) m).getJob();
			// report to job tracker and start the job
			tracker.submitMapJob(socket.getInetAddress().getHostName(), job);
			ret = new Message(job.getId() + "");
			break;
		case "status":
			// return the percentage of the jobs
			int jobID = ((JobMessage) m).getJob().getId();
			ret = new Message(tracker.getPercent(jobID));
			break;
		// message from slaves
		case "hi":
			// first message from a slave; get the slaveID and return
			int slaveID = tracker.addSlave(socket.getInetAddress()
					.getHostName());
			ret = new Message(String.valueOf(slaveID));
			slaveMonitor.resetSlave(slaveID);
			System.out.println("Slave #" + slaveID + "("
					+ socket.getInetAddress().getHostName() + ") connected");
			break;
		case "idle":
			// slave reports its work status
			WorkMessage msg = (WorkMessage) m;
			// get slave's available slot for tasks
			int mapSlot = msg.getMapSlot();
			int reduceSlot = msg.getReduceSlot();
			if (mapSlot == 0 && reduceSlot == 0) {
				ret = new Message("ACK");
			} else {
				int i = msg.getSlaveID();
				// assign slaves with tasks
				ArrayDeque<MapTask> maps = tracker.assignMapTask(i, mapSlot);
				ArrayDeque<ReduceTask> reduces = tracker.assignReduceTask(i,
						reduceSlot);
				if (maps.size() == 0 && reduces.size() == 0) {
					ret = new Message("ACK");
				} else {
					ret = new TaskMessage("todo");
					((TaskMessage) ret).setMapTask(maps);
					((TaskMessage) ret).setReduceTask(reduces);
				}
			}
			// job tracker marks which tasks are finished
			tracker.markDone(msg.getFinishedTask());
			// monitor resets the respond time of the slave
			slaveMonitor.resetSlave(msg.getSlaveID());
			break;
		case "busy":
			// slave is busy; master do nothing
			ret = new Message("ACK");
			// monitor resets the respond time of the slave
			slaveMonitor.resetSlave(((WorkMessage) m).getSlaveID());
			break;
		case "slave":
			// slave asks for the current slave information
			ret = new ShowSlaveMessage("slave");
			slaveMonitor.resetSlave(((WorkMessage) m).getSlaveID());
			// return the current slave information
			((ShowSlaveMessage) ret).setSlaveList(tracker.getSlaveList());
			break;
		default:
			break;
		}
		return ret;
	}