public synchronized HeartbeatResponse submitHeartbeat(TaskTrackerStatus taskTrackerStatus,
			boolean canAskForNewTasks, boolean isFirstContact, int responseID) throws RemoteException {
		Log.write("Got heartbeat from:" + taskTrackerStatus.getTaskTrackerID() + " canAskForNewTasks:"
				+ canAskForNewTasks + " isFirstContact:" + isFirstContact + " responseID:" + responseID);
		long now = System.currentTimeMillis();

		HeartbeatResponse prevHeartbeatResponse = taskTrackerToHeartbeatResponseMap.get(taskTrackerStatus
				.getTaskTrackerID());
		if (!isFirstContact) {
			// If this isn't the 'initial contact' from the tasktracker,
			// there is something seriously wrong if the JobTracker has
			// no record of the 'previous heartbeat'; if so, ask the
			// tasktracker to re-initialize itself.
			if (prevHeartbeatResponse == null || prevHeartbeatResponse.getResponseID() != responseID) {
				Log.warn("Serious wrong with " + taskTrackerStatus.getTaskTrackerID()
						+ " Ask the task tracker to restart.");
				// Reinit
				HeartbeatResponse response = new HeartbeatResponse(responseID);
				response.addTaskTrackerAction(new ReinitAction());
				return response;
			}
		}

		int newRespondID = responseID + 1;
		if (!processHeartbeat(taskTrackerStatus, isFirstContact)) {
			Log.warn("Serious wrong with " + taskTrackerStatus.getTaskTrackerID() + " Ask the task tracker to restart.");
			// Reinit
			HeartbeatResponse response = new HeartbeatResponse(responseID);
			response.addTaskTrackerAction(new ReinitAction());
			return response;
		}

		// Init response to task tracker
		HeartbeatResponse heartbeatResponse = new HeartbeatResponse(newRespondID);

		// Get new tasks if possible
		if (canAskForNewTasks) {
			// Assign tasks
			List<Task> taskList = null;
			try {
				taskList = taskScheduler.assignTasks(taskTrackerStatus);
			} catch (IOException e) {
				Log.warn("IOException happens during assign tasks to " + taskTrackerStatus.getTaskTrackerID());
			}

			if (taskList != null) {
				for (Task task : taskList) {
					Log.write("Launch task " + task.getTaskAttemptID() + " on " + taskTrackerStatus.getTaskTrackerID());
					heartbeatResponse.addTaskTrackerAction(new LaunchAction(task));
				}
			}
		}

		// Update heartbeat response map
		taskTrackerToHeartbeatResponseMap.put(taskTrackerStatus.getTaskTrackerID(), heartbeatResponse);
		return heartbeatResponse;
	}