/**
 * 
 */
package com.evolveum.midpoint.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;

/**
 * @author Radovan Semancik
 * 
 */
public class ClassPathUtil {

	public static Trace LOGGER = TraceManager.getTrace(ClassPathUtil.class);

	public static Set<Class> listClasses(String packageName) {

		Set<Class> classes = new HashSet<Class>();

		String path = packageName.replace('.', '/');
		Enumeration<URL> resources = null;
		try {//HACK this is not available use LOGGER
			resources = LOGGER.getClass().getClassLoader().getResources(path);
		} catch (IOException e) {
			LOGGER.error("Classloader scaning error for " + path, e);
		}

		while (resources.hasMoreElements()) {
			URL candidateUrl = resources.nextElement();
			LOGGER.debug("Candidates from: " + candidateUrl.getPath());

			// test if it is a directory or JAR
			if ("file".contentEquals(candidateUrl.getProtocol())) {
				classes.addAll(getFromDirectory(candidateUrl, packageName));

			} else if ("jar".contentEquals(candidateUrl.getProtocol())) {
				classes.addAll(getFromJar(candidateUrl, packageName));

			}
		}

		return classes;
	}

	/**
	 * Get clasess from JAR
	 * 
	 * @param candidateUrl
	 * @param packageName
	 * @return
	 */
	private static Collection<? extends Class> getFromJar(URL srcUrl, String packageName) {
		Set<Class> classes = new HashSet<Class>();
		// sample:
		// file:/C:/.m2/repository/test-util/1.9-SNAPSHOT/test-util-1.9-SNAPSHOT.jar!/test-data/opendj.template
		// output:
		// /C:/.m2/repository/test-util/1.9-SNAPSHOT/test-util-1.9-SNAPSHOT.jar
		String srcName = srcUrl.getPath().substring(5).split("!/")[0];

		JarFile jar = null;
		try {
			jar = new JarFile(srcName);
		} catch (IOException ex) {
			LOGGER.error("Error during open JAR {} " + srcName, ex);
			return classes;
		}
		String path = packageName.replace('.', '/');
		Enumeration<JarEntry> entries = jar.entries();
		LOGGER.debug("PATH:" + path);
		
		JarEntry e;
		while (entries.hasMoreElements()) {
			e = entries.nextElement();
			//get name and replace inner class
			String name = e.getName().replace('$', '/');
			//NOTICE: inner class are seperated and anonymous are part of the listing !! 
			
			// skip other files in other packas and skip non class files
			if (! name.contains(path) || ! name.contains(".class")) {
				continue;
			}
			//Skip all that are not in package
			if ( name.matches(path +"/.+/.*.class")) {
				continue;
			}
			
			LOGGER.info("JAR Candidate: {}", name);
			try {// to create class
				
				//Convert name back to package
				classes.add(Class.forName(name.replace('/', '.').replace(".class", "")));
			} catch (ClassNotFoundException ex) {
				LOGGER.error("Error during loading class {} from {}. ", name, jar.getName());
			}
		}
		
		try {
			jar.close();
		} catch (IOException ex) {
			LOGGER.error("Error during close JAR {} " + srcName, ex);
			return classes;
		}
		
		return classes;
	}

	/**
	 * get classes from directory
	 * 
	 * @param candidateUrl
	 * @param packageName
	 * @return
	 */
	private static Collection<Class> getFromDirectory(URL candidateUrl, String packageName) {
		Set<Class> classes = new HashSet<Class>();

		// Directory preparation
		File dir = null;
		try {
			dir = new File(candidateUrl.toURI());
		} catch (URISyntaxException e) {
			LOGGER.error("NEVER HAPPEND -- Wrong URI: " + candidateUrl.getPath(), e);
			return classes;
		}

		// Skip if it is directory
		if (!dir.isDirectory()) {
			LOGGER.warn("   Skip: {} is not a directory", candidateUrl.getPath());
			return classes;
		}

		// List directory
		String[] dirList = dir.list();
		for (int i = 0; i < dirList.length; i++) {
			// skip directories
			if (!dirList[i].contains(".class")) {
				continue;
			}
			try {// to create class
				LOGGER.info("DIR Candidate: {}", dirList[i]);
				classes.add(Class.forName(packageName + "." + dirList[i].replace(".class", "")));
			} catch (ClassNotFoundException e) {
				LOGGER.error("Error during loading class {} from {}. ", dirList[i], dir.getAbsolutePath());
			}
		}
		return classes;
	}
}

@@ -173,32 +173,53 @@
 o.OutputStream;%0A
+import java.net.URI;%0A
 import java.net.
@@ -2109,21 +2109,8 @@
 ().s
-ubstring(5).s
 plit
@@ -2120,16 +2120,352 @@
 /%22)%5B0%5D;%0A
+%0A%09%09//Probaly hepls fix error in windows with URI%0A%09%09File jarTmp = null;%0A%09%09try %7B%0A%09%09%09 jarTmp = new File(new URI(srcName));%0A%09%09%7D catch (URISyntaxException ex) %7B%0A%09%09%09LOGGER.error(%22Error converting jar %22 + srcName + %22 name to URI:%22,ex);%0A%09%09%09return classes;%0A%09%09%7D%0A%09%09%0A%09%09if (! jarTmp.isFile()) %7B%0A%09%09%09LOGGER.error(%22Is %7B%7D not a file.%22 , srcName);%0A%09%09%7D%0A%09%09
 %0A%09%09JarFi
@@ -2508,23 +2508,22 @@
 JarFile(
-srcName
+jarTmp
 );%0A%09%09%7D c
@@ -2580,27 +2580,24 @@
 ing open JAR
- %7B%7D
  %22 + srcName

Fix which may help in windows