001 /*
002 GRANITE DATA SERVICES
003 Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
004
005 This file is part of Granite Data Services.
006
007 Granite Data Services is free software; you can redistribute it and/or modify
008 it under the terms of the GNU Library General Public License as published by
009 the Free Software Foundation; either version 2 of the License, or (at your
010 option) any later version.
011
012 Granite Data Services is distributed in the hope that it will be useful, but
013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015 for more details.
016
017 You should have received a copy of the GNU Library General Public License
018 along with this library; if not, see <http://www.gnu.org/licenses/>.
019 */
020 package org.granite.osgi.classloader;
021
022 import java.util.Enumeration;
023 import java.util.HashSet;
024 import java.util.Iterator;
025 import java.util.Set;
026
027 import org.granite.logging.Logger;
028 import org.granite.messaging.service.annotations.RemoteDestination;
029 import org.osgi.framework.Bundle;
030
031 /**
032 * Granite DataService classloader
033 * scan packages then load qualified GDS classes.
034 * @author <a href="mailto:gembin@gmail.com">gembin@gmail.com</a>
035 * @since 1.1.0
036 */
037 public class ServiceClassLoader {
038 private static final Logger log=Logger.getLogger(ServiceClassLoader.class);
039 private static final String CLASS_SUFFIX = ".class";
040 private Set<String> classesSet = new HashSet<String>();
041 /**
042 * a Bundle which is used to load classes
043 */
044 private Bundle bundle;
045 public void setBundle(Bundle bundle) {
046 this.bundle = bundle;
047 }
048 /**
049 * @param className
050 * @return path of a class
051 */
052 private static String packageForPath(String className) {
053 return className.replace('.', '/');
054 }
055 /**
056 * @param path
057 * @return package of a class
058 */
059 private static String pathForPackage(String path) {
060 return path.replace('/', '.').replace('\\', '.');
061 }
062 /**
063 * resolve package to find all the classes in a specified package of a bundle
064 * @param packageNamePath
065 * @param recursive
066 */
067 private void resolvePackage(String packageNamePath,boolean recursive){
068 //if(log.isInfoEnabled())
069 // log.info("Resolving..."+packageNamePath);
070 @SuppressWarnings("unchecked")
071 Enumeration<String> en = bundle.getEntryPaths(packageNamePath);
072 if (en != null) {
073 while (en.hasMoreElements()) {
074 String entryPath = en.nextElement();
075 //recursive subpackages if wildcard is presented
076 if(recursive && entryPath.endsWith("/")){
077 resolvePackage(entryPath,recursive);
078 }else if(entryPath.endsWith(CLASS_SUFFIX)){
079 String className = entryPath.substring(0,entryPath.length()- CLASS_SUFFIX.length());
080 classesSet.add(pathForPackage(className));
081 }
082 }
083 }
084 }
085 /**
086 * @param className
087 * @return valid Service class annotated with @RemoteDestination
088 */
089 public Class<?> loadClass(String className){
090 try {
091 Class<?> clazz = bundle.loadClass(className);
092 if (clazz.isAnnotationPresent(RemoteDestination.class)) {
093 if(log.isInfoEnabled())
094 log.info(clazz.toString() + " is a valid GDS Service");
095 return clazz;
096 }
097 } catch (ClassNotFoundException e) {
098 e.printStackTrace();
099 }
100 return null;
101 }
102 /**
103 * Scan the packages and load all the qualified GraniteDS classes
104 * @param packages
105 * @return a set of valid Service classes annotated with @RemoteDestination
106 */
107 public Set<Class<?>> loadClasses(String[] packages) {
108 Set<Class<?>> classes = new HashSet<Class<?>>();
109 if (packages != null){
110 for (int i = 0; i < packages.length; i++) {
111 String packageName = packages[i];
112 if (bundle != null) {
113 boolean recursive=packageName.endsWith("*");
114 if(recursive)
115 packageName=packageName.substring(0, packageName.length()-2);//remove wildcard '*'
116 resolvePackage(packageForPath(packageName),recursive);
117 Iterator<String> it=classesSet.iterator();
118 while(it.hasNext()){
119 Class<?> clazz=null;
120 try {
121 clazz = bundle.loadClass(it.next());
122 if (clazz!=null && clazz.isAnnotationPresent(RemoteDestination.class)) {
123 if(log.isInfoEnabled())
124 log.info(clazz.toString() + " is a valid GDS Service");
125 classes.add(clazz);
126 }
127 } catch (ClassNotFoundException e) {
128 log.error("Service class not found", e);
129 }
130 }
131 } else {
132 if(log.isInfoEnabled())
133 log.info("Bundle is not specified, cannot load classes!!");
134 }
135 }
136 }
137 return classes;
138 }
139 }