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. * * * * BusinessAdmin * * * * 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 description = new ArrayList(); 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 description = new ArrayList(); 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 description = new ArrayList(); 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 description = new ArrayList(); 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. * * CalculatorServlet * Admin * * * 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 list = new ArrayList(); 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 listFilesAndFolders(String folder, int tabCounter) { List list = new ArrayList(); 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 list = new ArrayList(); 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 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 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); } }