001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * bstefanescu 018 */ 019package org.nuxeo.ecm.webengine.jaxrs; 020 021import java.lang.reflect.Array; 022import java.util.ArrayList; 023 024import org.osgi.framework.Bundle; 025 026/** 027 * Some helper methods for parsing configuration and loading contributed servlets or filters. 028 * 029 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 030 */ 031public class Utils { 032 033 /** 034 * Load classes from a list of class references given as a comma separated string list. 035 * 036 * @param classRefs the string containing the list of class references 037 * @return an array of the loaded classes 038 */ 039 public static Class<?>[] loadClasses(String classRefs) throws ClassNotFoundException, BundleNotFoundException { 040 return loadClasses(classRefs, ','); 041 } 042 043 /** 044 * Load classes from a list of class references given as a 'sep' separated string list. 045 * 046 * @param classRefs the string containing the list of class references 047 * @param sep the separator character used to separate class references in the string. 048 * @return an array of the loaded classes 049 */ 050 public static Class<?>[] loadClasses(String classRefs, char sep) throws ClassNotFoundException, 051 BundleNotFoundException { 052 StringBuilder buf = null; 053 ArrayList<Class<?>> classes = new ArrayList<>(); 054 char[] chars = classRefs.toCharArray(); 055 for (char c : chars) { 056 if (c <= ' ') { 057 continue; 058 } else if (c == sep) { 059 if (buf != null) { 060 classes.add(loadClass(buf.toString())); 061 buf = null; 062 } 063 } else { 064 if (buf == null) { 065 buf = new StringBuilder(); 066 } 067 buf.append(c); 068 } 069 } 070 071 if (buf != null) { 072 classes.add(loadClass(buf.toString())); 073 } 074 075 return classes.toArray(new Class<?>[0]); 076 } 077 078 /** 079 * Get class instances for the given class references string 080 * 081 * @param componentType the type of the expected array component 082 * @see #loadClasses(String) 083 */ 084 public static <T> T[] newInstances(Class<T> componentType, String classRefs) throws ReflectiveOperationException, 085 BundleNotFoundException { 086 return newInstances(componentType, classRefs, ','); 087 } 088 089 /** 090 * Get class instances for the given class references string 091 * 092 * @see #loadClasses(String, char) 093 */ 094 @SuppressWarnings("unchecked") 095 public static <T> T[] newInstances(Class<T> componentType, String classRefs, char sep) 096 throws ReflectiveOperationException, BundleNotFoundException { 097 Class<?>[] classes = loadClasses(classRefs, sep); 098 T[] ar = (T[]) Array.newInstance(componentType, classes.length); 099 for (int i = 0; i < classes.length; i++) { 100 ar[i] = (T) classes[i].getDeclaredConstructor().newInstance(); 101 } 102 return ar; 103 } 104 105 /** 106 * Load a class from a class reference string. The class reference string is in the format: 107 * <code>bundleSymbolicName:className</code> or <code>className</code>. If no bundle symbolic name is given the 108 * class will be loaded using the class loader of the {@link Utils} class. 109 * <p> 110 * The bundle will be resolved to the last version of the bundle (in case when different bundle versions are found) 111 */ 112 public static Class<?> loadClass(String classRef) throws ClassNotFoundException, BundleNotFoundException { 113 int i = classRef.indexOf(':'); 114 if (i == -1) { 115 // use the current bundle class loader 116 return Activator.getInstance().getContext().getBundle().loadClass(classRef.trim()); 117 } else { 118 return loadClass(classRef.substring(0, i).trim(), classRef.substring(i + 1).trim()); 119 } 120 } 121 122 /** 123 * Get a class proxy reference for the given class reference 124 */ 125 public static ClassRef getClassRef(String classRef) throws ClassNotFoundException, BundleNotFoundException { 126 return getClassRef(classRef, null); 127 } 128 129 public static ClassRef getClassRef(String classRef, Bundle bundle) throws ClassNotFoundException, 130 BundleNotFoundException { 131 int i = classRef.indexOf(':'); 132 if (i == -1) { 133 // use the current bundle class loader 134 if (bundle == null) { 135 bundle = Activator.getInstance().getContext().getBundle(); 136 } 137 return new ClassRef(bundle, bundle.loadClass(classRef.trim())); 138 } else { 139 String bundleId = classRef.substring(0, i).trim(); 140 String className = classRef.substring(i + 1).trim(); 141 Bundle[] bundles = Activator.getInstance().getPackageAdmin().getBundles(bundleId, null); 142 if (bundles != null) { 143 return new ClassRef(bundles[0], bundles[0].loadClass(className)); 144 } else { 145 throw new BundleNotFoundException(bundleId); 146 } 147 } 148 } 149 150 /** 151 * Load a class given the owner bundle and the class name. 152 * <p> 153 * The bundle will be resolved to the last version of the bundle (in case when different bundle versions are found) 154 */ 155 public static Class<?> loadClass(String bundleId, String className) throws ClassNotFoundException, 156 BundleNotFoundException { 157 Bundle[] bundles = Activator.getInstance().getPackageAdmin().getBundles(bundleId, null); 158 if (bundles != null) { 159 return bundles[0].loadClass(className); 160 } else { 161 throw new BundleNotFoundException(bundleId); 162 } 163 } 164 165 /** 166 * Create a new object of the given class in the given bundle. The class should provide a no-args empty constructor. 167 * <p> 168 * The bundle will be resolved to the last version of the bundle (in case when different bundle versions are found) 169 * 170 * @see #loadClass(String, String) 171 */ 172 public static Object newInstance(String bundleId, String className) throws ReflectiveOperationException, 173 BundleNotFoundException { 174 return loadClass(bundleId, className).getDeclaredConstructor().newInstance(); 175 } 176 177 /** 178 * Create a new object of the given a class reference. 179 * <p> 180 * The bundle will be resolved to the last version of the bundle (in case when different bundle versions are found) 181 * 182 * @see #loadClass(String, String) 183 */ 184 public static Object newInstance(String classRef) throws ReflectiveOperationException, BundleNotFoundException { 185 return loadClass(classRef).getDeclaredConstructor().newInstance(); 186 } 187 188 public static class ClassRef { 189 protected Bundle bundle; 190 191 protected Class<?> clazz; 192 193 public ClassRef(Bundle bundle, Class<?> clazz) { 194 this.bundle = bundle; 195 this.clazz = clazz; 196 } 197 198 public Class<?> get() { 199 return clazz; 200 } 201 202 public Bundle bundle() { 203 return bundle; 204 } 205 206 public Object newInstance() throws ReflectiveOperationException { 207 return clazz.getDeclaredConstructor().newInstance(); 208 } 209 210 @Override 211 public String toString() { 212 if (bundle != null) { 213 return bundle.getSymbolicName() + ":" + clazz.getName(); 214 } 215 return clazz.getName(); 216 } 217 218 } 219 220}