public static void main(String[] args) throws ConfigurationException,
			IOException, InterruptedException {
		double startTime = System.currentTimeMillis();
		if (args.length != 4) {
			System.out
					.println("Usage:[src directory(local)][destination directory (remote)][file filter][num threads]");
			return;
		}

		int numThreads = Integer.parseInt(args[3]);

		TwisterConfigurations configs = null;
		try {
			configs = TwisterConfigurations.getInstance();
		} catch (ConfigurationException e) {
			System.err.println(e.getMessage());
			System.exit(-1);
		}

		ExecutorService taskExecutor = Executors.newFixedThreadPool(numThreads);

		Object lock = new Object();
		boolean errors = false;

		File srcDir = new File(args[0]);
		if (!srcDir.exists()) {
			System.err
					.println("Invalid input directory. Directory does not exist.");
			System.exit(-1);
		}
		List<String> files = getListOfFiles(args[0], args[2]);
		if (files.size() == 0) {
			System.err.println("No files to copy.");
			System.exit(-1);
		}
		List<String> hosts = getListOfNodes();
		if (hosts.size() == 0) {
			System.err.println("No compute nodes specified in nodes file.");
			System.exit(-1);
		}
		List<List<String>> groups = groupFilesToHosts(files, hosts.size());

		int count = 0;
		String host;
		String dest;
		String dataDir = (configs.getLocalDataDir() + "/" + args[1] + "/").replace(
				"//", "/");
		for (List<String> group : groups) {
			host = hosts.get(count++);
			dest = host + ":" + dataDir;
			for (String file : group) {
				taskExecutor.execute(new FileCopyandMvThread(file, dest, lock,
						errors));
			}
		}

		taskExecutor.shutdown();
		try {
			taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
		} catch (InterruptedException e) {
			System.exit(-1);
		}
		double endTime = System.currentTimeMillis();
		System.out.println("Total Data Copy Time = " + (endTime - startTime)
				/ 1000 + " Seconds.");

		if (errors) {
			System.exit(-1);
		} else {
			System.exit(0);
		}
	}