package grizzly;

import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.annotation.Resources;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RunAs;
import javax.xml.ws.WebServiceRef;

import com.sun.grizzly.http.servlet.deployer.GrizzlyWebServerDeployer;
import com.sun.grizzly.http.webxml.schema.EnvEntry;
import com.sun.grizzly.http.webxml.schema.LifecycleCallback;
import com.sun.grizzly.http.webxml.schema.MessageDestinationRef;
import com.sun.grizzly.http.webxml.schema.PortComponentRef;
import com.sun.grizzly.http.webxml.schema.ResourceRef;
import com.sun.grizzly.http.webxml.schema.SecurityRole;
import com.sun.grizzly.http.webxml.schema.ServiceRef;
import com.sun.grizzly.http.webxml.schema.Servlet;
import com.sun.grizzly.http.webxml.schema.WebApp;

public class AnnotationParser {

	/*
	 * This annotation is used to define the security roles that comprise the
	 * security model of the application. This annotation is specified on a
	 * class, and it typically would be used to define roles that could be
	 * tested (i.e., by calling isUserInRole) from within the methods of the
	 * annotated class. It could also be used to declare application roles that
	 * are not implicitly declared as the result of their use in a
	 * 
	 * @DeclareRoles annotation on the class implementing the javax.servlet.
	 * Servlet interface or a subclass thereof. Following is an example of how
	 * this annotation would be used.
	 * 
	 * @DeclareRoles("BusinessAdmin") public class CalculatorServlet { //... }
	 * Declaring @DeclaresRoles ("BusinessAdmin") is equivalent to defining the
	 * following in the web.xml. 
	 * 
	 * <web-app> 
	 *    <security-role>
	 *       <role-name>BusinessAdmin</role-name> 
	 *    </security-role> 
	 * </web-app>
	 * 
	 * JSR-250
	 */
	protected void parseDeclareRoles(WebApp webapp, Class<?> clazz) throws Exception {

		if (webapp == null || clazz == null) {
			return;
		}

		DeclareRoles an = (DeclareRoles) clazz.getAnnotation(DeclareRoles.class);

		if (an != null) {
			System.out.println(an.toString());

			for (String value : an.value()) {
				if(value!=null){
					SecurityRole role = new SecurityRole();
					role.setRoleName(value);
	
					webapp.getSecurityRole().add(role);
				}
			}

		} else {
			System.out.println("Annotation not found");
		}

	}

	/*
	 * Enterprise JavaBeansTM 3.0 (EJB) components may referenced from a web
	 * component using the @EJB annotation. The @EJB annotation provides the
	 * equivalent functionality of declaring the ejb-ref or ejb-local-ref
	 * elements in the deployment descriptor. Fields that have a corresponding
	 * 
	 * @EJB annotation are injected with the a reference to the corresponding
	 * EJB component.
	 * 
	 * An example:
	 * 
	 * @EJB private ShoppingCart myCart;
	 * 
	 * In the case above a reference to the EJB component “myCart” is injected
	 * as the value of the private field “myCart” prior to the classs declaring
	 * the injection being made available. The behavior the @EJB annotation is
	 * further detailed in section 15.5 of the EJB 3.0 specification (JSR220).
	 */
	protected void parseEJB(WebApp webapp, Class<?> clazz) throws Exception {
		if (webapp == null || clazz == null) {
			return;
		}

		System.out.println("Not Implemented");
	}

	/*
	 * The @EJBs annotation allows more than one @EJB annotations to be declared
	 * on a single resource. An example:
	 * 
	 * @EJBs({@EJB(Calculator), @EJB(ShoppingCart)}) public class
	 * ShoppingCartServlet { //... } The example above the EJB components
	 * ShoppingCart and Calculator are made available to ShoppingCartServlet.
	 * The ShoppingCartServlet must still look up the references using JNDI but
	 * the EJBs do not need to declared in the web.xml file
	 * 
	 * The @EJBs annotation is discussed in further detailed in section 15.5 of
	 * the EJB 3.0 specification (JSR220).
	 */
	protected void parseEJBs(WebApp webapp, Class<?> clazz) throws Exception {
		if (webapp == null || clazz == null) {
			return;
		}

		System.out.println("Not Implemented");
	}

	/*
	 * The @Resource annotation is used to declare a reference to a resource
	 * such as a data source, Java Messaging Service (JMS) destination, or
	 * environment entry. This annotation is equivalent to declaring a
	 * resource-ref, message-destinationref or env-ref, or resource-env-ref
	 * element in the deployment descriptor. The @Resource annotation is
	 * specified on a class, method or field. The container is responsible
	 * injecting references to resources declared by the
	 * 
	 * @Resource annotation and mapping it to the proper JNDI resources. See the
	 * Java EE Specification Chapter 5 for further details. An example of a
	 * 
	 * @Resource annotation follows:
	 * 
	 * @Resource private javax.sql.DataSource catalogDS; public
	 * getProductsByCategory() { // get a connection and execute the query
	 * Connection conn = catalogDS.getConnection(); .. }
	 * 
	 * JSR-250
	 */
	protected void parseResource(WebApp webapp, Class<?> clazz) throws Exception {
		if (webapp == null || clazz == null) {
			return;
		}
		
		Resource an = (Resource)clazz.getAnnotation(Resource.class);
		
		if(an!=null){
			System.out.println(an.toString());
			populateResource(webapp, an);
		}
		
		for (Field field : clazz.getFields()) {
			Resource resource = (Resource) field.getAnnotation(Resource.class);
			
			if (resource != null) {
				System.out.println(resource.toString() + " " + field.toString());
				populateResource(webapp, resource);
				
			}
		}
		
		for (Method method : clazz.getMethods()) {
			Resource resource = (Resource) method.getAnnotation(Resource.class);
			
			if (resource != null) {
				System.out.println(resource.toString() + " " + method.toString());
				populateResource(webapp, resource);
				
			}
		}
		
		for (Field field : clazz.getFields()) {
			Resource resource = (Resource) field.getAnnotation(Resource.class);
			
			if (resource != null) {
				System.out.println(resource.toString() + " " + field.toString());
				populateResource(webapp, resource);
				
			}
		}
		
		if(webapp.getPostConstruct().size()==0){
			System.out.println("Annotation not found");
		}
	}

	/*
	 * The PersistenceContexts annotation allows more than one
	 * 
	 * @PersistenceContext to be declared on a resource. The behavior the
	 * 
	 * @PersistenceContext annotation is further detailed in section 8.4.1 of
	 * the Java Persistence document which is part of the EJB 3.0 specification
	 * (JSR220) and in section 15.11 of the EJB 3.0 specification
	 * 
	 * @PersistenceContext (type=EXTENDED) EntityManager em;
	 */
	protected void parsePersistenceContext(WebApp webapp, Class<?> clazz) throws Exception {
		if (webapp == null || clazz == null) {
			return;
		}

		System.out.println("Not Implemented");
	}

	/*
	 * The @PersistenceUnit annotation provides Enterprise Java Beans components
	 * declared in a servlet a reference to a entity manager factory. The entity
	 * manager factory is bound to a separate persistence.xml configuration file
	 * as described in section 5.10 of the EJB 3.0 specification (JSR220). An
	 * example:
	 * 
	 * @PersistenceUnit EntityManagerFactory emf; The behavior the
	 * 
	 * @PersistenceUnit annotation is further detailed in section 8.4.2 of the
	 * Java Persistence document which is part of the EJB 3.0 specification
	 * (JSR220) and in section 15.10 of the EJB 3.0 specification.
	 */
	protected void parsePersistenceUnit(WebApp webapp, Class<?> clazz) throws Exception {
		if (webapp == null || clazz == null) {
			return;
		}

		System.out.println("Not Implemented");
	}

	/*
	 * This annotation allows for more than one @PersistentUnit annotations to
	 * be declared on a resource. The behavior the @PersistenceUnits annotation
	 * is further detailed in section 8.4.2 of the Java Persistence document
	 * which is part of the EJB 3.0 specification (JSR220) and in section 15.10
	 * of the EJB 3.0 specification..
	 */
	protected void parsePersistenceUnits(WebApp webapp, Class<?> clazz) throws Exception {
		if (webapp == null || clazz == null) {
			return;
		}

		System.out.println("Not Implemented");
	}

	/*
	 * The @PostConstruct annotation is declared on a method that does not take
	 * any arguments, and must not throw any checked expections. The return
	 * value must be void. The method MUST be called after the resources
	 * injections have been completed and before any lifecycle methods on the
	 * component are called. An example:
	 * 
	 * @PostConstruct public void postConstruct() { ... } The example above
	 * shows a method using the @PostConstruct annotation.
	 */
	protected void parsePostConstruct(WebApp webapp, Class<?> clazz) throws Exception {
		if (webapp == null || clazz == null) {
			return;
		}

		for (Method method : clazz.getMethods()) {
			PostConstruct an = (PostConstruct) method.getAnnotation(PostConstruct.class);
			
			if (an != null) {
				System.out.println(an.toString() + " " + method.toString());
				
				LifecycleCallback callback = new LifecycleCallback();
				callback.setLifecycleCallbackClass(clazz.getName());
				callback.setLifecycleCallbackMethod(method.getName());
				
				webapp.getPostConstruct().add(callback);
			}
		}
		
		if(webapp.getPostConstruct().size()==0){
			System.out.println("Annotation not found");
		}
		
	}

	/*
	 * The @PreDestroy annotation is declared on a method of a container managed
	 * component. The method is called prior to component being reomvoed by the
	 * container. An example:
	 * 
	 * @PreDestroy public void cleanup() { // clean up any open resources ... }
	 * The method annotated with @PreDestroy must return void and must not throw
	 * a checked exception. The method may be public, protected, package private
	 * or private. The method must not be static however it may be final.
	 * 
	 * JSR-250
	 */
	protected void parsePreDestroy(WebApp webapp, Class<?> clazz) throws Exception {
		if (webapp == null || clazz == null) {
			return;
		}

		for (Method method : clazz.getMethods()) {
			PreDestroy an = (PreDestroy) method.getAnnotation(PreDestroy.class);
			
			if (an != null) {
				System.out.println(an.toString() + " " + method.toString());
				
				LifecycleCallback callback = new LifecycleCallback();
				callback.setLifecycleCallbackClass(clazz.getName());
				callback.setLifecycleCallbackMethod(method.getName());
				
				webapp.getPreDestroy().add(callback);
			}
		}
		
		if(webapp.getPostConstruct().size()==0){
			System.out.println("Annotation not found");
		}
	}
	
	private static void populateResource(WebApp webapp, Resource resource) throws Exception {
		if (webapp == null || resource == null) {
			return;
		}
		
		if(resource.type().getCanonicalName().endsWith("Service")){
			// service-ref element
            ServiceRef serviceRef = new ServiceRef();
            
            serviceRef.setServiceRefName(resource.name());
            serviceRef.setServiceRefType(resource.type().getName());
            serviceRef.setMappedName(resource.mappedName());
            
            List<String> description = new ArrayList<String>();
            description.add(resource.description());
            serviceRef.setDescription(description);
            
            webapp.getServiceRef().add(serviceRef);
            
		} else if (resource.type().getCanonicalName().equals("javax.sql.DataSource") ||
				resource.type().getCanonicalName().endsWith("ConnectionFactory") ||
                resource.type().getCanonicalName().equals("javax.mail.Session") ||
                resource.type().getCanonicalName().equals("java.net.URL")){
			
			// ?????
			
			// resource-ref element  or resource-env-ref element
			
			// resource-ref element
			
			ResourceRef resourceRef = new ResourceRef();
			
			List<String> description = new ArrayList<String>();
            description.add(resource.description());
            resourceRef.setDescription(description);
            
            resourceRef.setMappedName(resource.mappedName());
           
            if (resource.authenticationType() == Resource.AuthenticationType.CONTAINER) {
            	resourceRef.setResAuth("Container");
            }
            else if (resource.authenticationType() == Resource.AuthenticationType.APPLICATION) {
            	resourceRef.setResAuth("Application");
            }
            
            resourceRef.setResRefName(resource.name());
            resourceRef.setResSharingScope(resource.shareable() ? "Shareable" : "Unshareable");
            resourceRef.setResType(resource.type().getName());
			
			webapp.getResourceRef().add(resourceRef);
			
		} else if (resource.type().getCanonicalName().equals("javax.jms.Queue") ||
				resource.type().getCanonicalName().equals("javax.jms.Topic")) {
            
            // message-destination-ref
            MessageDestinationRef messageRef = new MessageDestinationRef();
            
            List<String> description = new ArrayList<String>();
            description.add(resource.description());
            messageRef.setDescription(description);
            
            messageRef.setMappedName(resource.mappedName());
            messageRef.setMessageDestinationRefName(resource.name());
            messageRef.setMessageDestinationType(resource.type().getName());
            messageRef.setMessageDestinationUsage(resource.mappedName());
            
            webapp.getMessageDestinationRef().add(messageRef);
            
        } else if (resource.type().getCanonicalName().equals("java.lang.String") ||
        		resource.type().getCanonicalName().equals("java.lang.Character") ||
        		resource.type().getCanonicalName().equals("java.lang.Integer") ||
        		resource.type().getCanonicalName().equals("java.lang.Boolean") ||
        		resource.type().getCanonicalName().equals("java.lang.Double") ||
        		resource.type().getCanonicalName().equals("java.lang.Byte") ||
        		resource.type().getCanonicalName().equals("java.lang.Short") ||
        		resource.type().getCanonicalName().equals("java.lang.Long") ||
        		resource.type().getCanonicalName().equals("java.lang.Float")) {
            
            // env-entry element
            
            EnvEntry entry = new EnvEntry();
            
            entry.setEnvEntryName(resource.name());
            entry.setEnvEntryValue(resource.mappedName());
            entry.setEnvEntryType(resource.type().getName());
            entry.setMappedName(resource.mappedName());
            
            List<String> description = new ArrayList<String>();
            description.add(resource.description());
            entry.setDescription(description);
            
            webapp.getEnvEntry().add(entry);
            
        } 
		
	}

	/*
	 * The @Resources annotation acts as a container for multiple @Resource
	 * annotations because the Java MetaData specification does not allow for
	 * multiple annotations with the same name on the same annotation target. An
	 * example:
	 * 
	 * @Resources ({
	 * 
	 * @Resource(name=”myDB” type=javax.sql.DataSource),
	 * 
	 * @Resource(name=”myMQ” type=javax.jms.ConnectionFactory) }) public class
	 * CalculatorServlet { //... } In the example above a JMS connection factory
	 * and a data source are made available to the CalculatorServlet by means of
	 * an @Resources annotation. The semantics of the @Resources annotation are
	 * further detailed in the Common Annotations for the JavaTM PlatformTM
	 * specifcation (JSR 250) section 2.4.
	 */
	protected void parseResources(WebApp webapp, Class<?> clazz) throws Exception {
		if (webapp == null || clazz == null) {
			return;
		}
		
		Resources an = (Resources) clazz.getAnnotation(Resources.class);

		if (an != null && an.value()!=null) {
			System.out.println(an.toString());
			
			for (Resource resource : an.value()) {
				populateResource(webapp, resource);
			}

		} else {
			System.out.println("Annotation not found");
		}
		
		for (Method method : clazz.getMethods()) {
			Resources resources = (Resources) method.getAnnotation(Resources.class);
			
			if (resources != null && resources.value()!=null) {
				for (Resource resource : an.value()) {
					System.out.println(resource.toString() + " " + method.toString());
					populateResource(webapp, resource);
				}
				
			}
		}
		
		for (Field field : clazz.getFields()) {
			Resources resources = (Resources) field.getAnnotation(Resources.class);
			
			if (resources != null && resources.value()!=null) {
				for (Resource resource : an.value()) {
					System.out.println(resource.toString() + " " + field.toString());
					populateResource(webapp, resource);
				}
				
			}
		}
	}

	/*
	 * The @RunAs annotation is equivalent to the run-as element in the
	 * deployment descriptor. The @RunAs annotation may only be defined in
	 * classes implementing the javax.servlet.Servlet interface or a subclass
	 * thereof. An example:
	 * 
	 * @RunAs(“Admin”) public class CalculatorServlet {
	 * 
	 * @EJB private ShoppingCart myCart; public void doGet(HttpServletRequest,
	 * req, HttpServletResponse res) { //.... myCart.getTotal(); //.... } }
	 * //.... } The @RunAs(“Admin”) statement would be equivalent to defining
	 * the following in the web.xml. <servlet>
	 * 
	 * <servlet-name>CalculatorServlet</servlet-name>
	 *    <run-as>Admin</run-as>
	 * </servlet>
	 * 
	 * The example above shows how a servlet uses the @RunAs annotation to
	 * propagate the security identity “Admin” to an EJB component when the
	 * myCart.getTotal() method is called. For further details on propagating
	 * identities see SRV.14.3.1. For further details on the @RunAs annotation
	 * refer to the Common Annotations for the JavaTM PlatformTM specifcation
	 * (JSR 250) section 2.6
	 */
	protected void parseRunAs(WebApp webapp, Class<?> clazz) throws Exception {
		if (webapp == null || clazz == null) {
			return;
		}

		if (javax.servlet.Servlet.class.isAssignableFrom(clazz)) {
			RunAs an = (RunAs) clazz.getAnnotation(RunAs.class);
			
			if (an != null) {
				System.out.println(an.toString());
				
				com.sun.grizzly.http.webxml.schema.RunAs runAs = new com.sun.grizzly.http.webxml.schema.RunAs();
				runAs.setRoleName(an.value());
				
				
				Servlet servlet = new Servlet();
				servlet.setServletClass(clazz.getName());
				servlet.setRunAs(runAs);
				
				webapp.getServlet().add(servlet);

			} else {
				System.out.println("Annotation not found");
			}
			
		} else {
			System.out.println("Annotation not found");
		}
		
		

		
	}

	/*
	 * The @WebServiceRef annotation provides a reference to a web service in a
	 * web component in same way as a resource-ref element would in the
	 * deployment descriptor. An example:
	 * 
	 * @WebServiceRef private MyService service; 
	 * 
	 * In this example a reference to
	 * the web service “MyService” will be injected to the class declaring the
	 * annotation. This annotation and behavior are further detailed in the
	 * JAX-WS Specification (JSR 224) section 7.
	 */
	protected void parseWebServiceRef(WebApp webapp, Class<?> clazz) throws Exception {
		if (webapp == null || clazz == null) {
			return;
		}
		
		for (Field field : clazz.getFields()) {
			WebServiceRef an = (WebServiceRef) clazz.getAnnotation(WebServiceRef.class);
			
			if (an != null) {
				System.out.println(an.toString() + " " + field.toString());
				
				ServiceRef serviceRef = new ServiceRef();
				
				serviceRef.setMappedName(an.mappedName());
				serviceRef.setWsdlFile(an.wsdlLocation());
				serviceRef.setServiceRefName(an.name());
				serviceRef.setServiceRefType(an.type().getName());
				
				PortComponentRef portComponentRef = new PortComponentRef();
	            portComponentRef.setPortComponentLink(an.type().getCanonicalName());
	            
	            
				if (an.value() == null){
					serviceRef.setServiceInterface(an.type().getCanonicalName());
				}
	            
	            if (an.type().getCanonicalName().equals("Service")){
	            	serviceRef.setServiceInterface(an.type().getCanonicalName());
	            }
	            
	            if (an.type().getCanonicalName().equals("Endpoint")){
	            	portComponentRef.setServiceEndpointInterface(an.type().getCanonicalName());
	            }
	            
	            List<PortComponentRef> list = new ArrayList<PortComponentRef>();
	            list.add(portComponentRef);
	            
	            serviceRef.setPortComponentRef(list);
				
				webapp.getServiceRef().add(serviceRef);
			}
		}
		 
		
		System.out.println("Not Implemented");
		
		
	}

	/*
	 * This annotation allows for more than one @WebServiceRef annotations to be
	 * declared on a single resource. The behavior of this annotation is further
	 * detailed in the JAX-WS Specification (JSR 224) section 7.
	 */
	protected void parseWebServiceRefs(WebApp webapp, Class<?> clazz) throws Exception {
		if (webapp == null || clazz == null) {
			return;
		}
		/*
		WebServiceRefs an = (WebServiceRefs) clazz.getAnnotation(WebServiceRefs.class);

		if (an != null) {
			System.out.println(an.toString());
			/

		} else {
			System.out.println("Annotation not found");
		}
		*/
		
		System.out.println("Not Implemented");
	}

	/*
	 * javax.servlet.Servlet # javax.servlet.Filter #
	 * javax.servlet.ServletContextListener #
	 * javax.servlet.ServletContextAttributeListener #
	 * javax.servlet.ServletRequestListener #
	 * javax.servlet.ServletRequestAttributeListener #
	 * javax.servlet.http.HttpSessionListener #
	 * javax.servlet.http.HttpSessionAttributeListener
	 */
	public boolean isValid(Class<?> clazz) throws InstantiationException, IllegalAccessException {
		if (clazz == null) {
			return false;
		}

		if(javax.servlet.Servlet.class.isAssignableFrom(clazz) || 
				javax.servlet.Filter.class.isAssignableFrom(clazz) || 
				javax.servlet.ServletContextListener.class.isAssignableFrom(clazz) || 
				javax.servlet.ServletContextAttributeListener.class.isAssignableFrom(clazz) || 
				javax.servlet.ServletRequestListener.class.isAssignableFrom(clazz) ||
				javax.servlet.ServletRequestAttributeListener.class.isAssignableFrom(clazz) || 
				javax.servlet.http.HttpSessionListener.class.isAssignableFrom(clazz) || 
				javax.servlet.http.HttpSessionAttributeListener.class.isAssignableFrom(clazz)) {
				return true;
		}

		return false;

	}
	
	
	protected void parseAnnotation(Class<?> clazz, WebApp webapp) throws Exception {
		
		if (!isValid(clazz)) {
			return;
		}
		
		parseDeclareRoles(webapp, clazz);
		parseResource(webapp, clazz);
		parseResources(webapp, clazz);
		parsePostConstruct(webapp, clazz);
		parsePreDestroy(webapp, clazz);
		parseRunAs(webapp, clazz);
		parseWebServiceRef(webapp, clazz);
		parseWebServiceRefs(webapp, clazz);
		
		parsePersistenceContext(webapp, clazz);
		parsePersistenceUnit(webapp, clazz);
		parsePersistenceUnits(webapp, clazz);
		parseEJB(webapp, clazz);
		parseEJBs(webapp, clazz);
		
	}
	
	public List<String> listFilesAndFolders(String folder, int tabCounter) {

		
		List<String> list = new ArrayList<String>();
		
	    File file = new File(folder);

	    if (!file.exists() || !file.isDirectory()) {

	      System.out.println("Parameter is not a directory");
	      return list;

	    }

	    File[] fileArray = file.listFiles(new FileFilter() {
			
			@Override
			public boolean accept(File pathname) {
				if(pathname.isDirectory() || pathname.getName().endsWith(".class")){
					return true;
				}
				return false;
			}
		});

	    for (int i = 0; i < fileArray.length; i++) {

	      if (fileArray[i].isDirectory()) {
	    	  list.addAll(listFilesAndFolders(fileArray[i].getAbsolutePath(), tabCounter+1));
	    	  
	      } else {
	    	  // nous avons une class .. 
	    	  String toSkip = "WEB-INF" + File.separator + "classes" + File.separator;
	    	  
	    	  String path = fileArray[i].getPath(); 
	    	  path = path.substring(path.indexOf(toSkip)+toSkip.length());
	    	  
	    	  String classname = path.replace('\\', '/').replace('/', '.');
	    	  
	    	  list.add(classname);
	    	  
	      }
	    }
	    tabCounter--;

	    return list;
	  }
	
	
	public WebApp parseAnnotation(URLClassLoader classLoader) throws Exception {
		
		if(classLoader==null){
			return null;
		}
		
		WebApp webapp = new WebApp();
		
		URL urls[] = classLoader.getURLs();
		
		List<String> list = new ArrayList<String>();
		
		for (URL url : urls) {
			System.out.println("url=" + url.getProtocol() + " " + url.toString());
			
			if("file".equals(url.getProtocol())){
				
				if(url.getPath().endsWith("WEB-INF/lib/") || url.getPath().endsWith("WEB-INF/classes/")){
					File file = new File(url.toURI());
					System.out.println("file=" + file.getCanonicalPath());
					
					System.out.println("");
					
					if(file.isDirectory()){
						list.addAll(listFilesAndFolders(file.getCanonicalPath(),0));
					}
				}
				
			} else if("jar".equals(url.getProtocol())){
				
				JarURLConnection conn = (JarURLConnection) url.openConnection();
				
				JarFile jar = conn.getJarFile();
				
				Enumeration<JarEntry> en = jar.entries();
				
				while (en.hasMoreElements()) {
					JarEntry jarEntry = en.nextElement();
					
					String classname = jarEntry.getName();
					
					if(classname.endsWith(".class")){
						classname = classname.replace('\\', '/').replace('/', '.').replace('$', '.');
						System.out.println(classname);
						list.add(classname);
					}
				}
				
			}
			
		}
		
		
		System.out.println("List of classes : " + list.size());
		
		for (String classname : list) {
			System.out.println("class = " + classname);
			
			try {
				parseAnnotation(classLoader.loadClass(classname.substring(0,classname.indexOf(".class"))), webapp);
			} catch(Exception e){
				System.out.println("Not able to load this class=" + classname);
			}
		}
		
		
		return webapp;
	}

	/**
	 * @param args
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */
	public static void main(String[] args) throws Exception {

		AnnotationParser parser = new AnnotationParser();
		
		final Map.Entry<String, URLClassLoader> loaderEntry =
            GrizzlyWebServerDeployer.explodeAndCreateWebAppClassLoader("C:/workspace_personal/WebAnnotation/", new URLClassLoader(new URL[0]));
		
		URLClassLoader classLoader = loaderEntry.getValue();
		
		WebApp webapp = parser.parseAnnotation(classLoader);

		
		System.out.println(webapp);
		

	}

}