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*/ 020package org.granite.osgi.classloader; 021 022import java.util.Enumeration; 023import java.util.HashSet; 024import java.util.Iterator; 025import java.util.Set; 026 027import org.granite.logging.Logger; 028import org.granite.messaging.service.annotations.RemoteDestination; 029import 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 */ 037public 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}