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);
}
}