1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18 package android.filterfw.core; 19 20 import android.filterfw.core.Filter; 21 import android.util.Log; 22 23 import dalvik.system.PathClassLoader; 24 25 import java.lang.reflect.Constructor; 26 import java.lang.ClassLoader; 27 import java.lang.Thread; 28 import java.util.HashSet; 29 30 /** 31 * @hide 32 */ 33 public class FilterFactory { 34 35 private static FilterFactory mSharedFactory; 36 private HashSet<String> mPackages = new HashSet<String>(); 37 38 private static ClassLoader mCurrentClassLoader; 39 private static HashSet<String> mLibraries; 40 private static Object mClassLoaderGuard; 41 42 static { 43 mCurrentClassLoader = Thread.currentThread().getContextClassLoader(); 44 mLibraries = new HashSet<String>(); 45 mClassLoaderGuard = new Object(); 46 } 47 48 private static final String TAG = "FilterFactory"; 49 private static boolean mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE); 50 51 public static FilterFactory sharedFactory() { 52 if (mSharedFactory == null) { 53 mSharedFactory = new FilterFactory(); 54 } 55 return mSharedFactory; 56 } 57 58 /** 59 * Adds a new Java library to the list to be scanned for filters. 60 * libraryPath must be an absolute path of the jar file. This needs to be 61 * static because only one classloader per process can open a shared native 62 * library, which a filter may well have. 63 */ 64 public static void addFilterLibrary(String libraryPath) { 65 if (mLogVerbose) Log.v(TAG, "Adding filter library " + libraryPath); 66 synchronized(mClassLoaderGuard) { 67 if (mLibraries.contains(libraryPath)) { 68 if (mLogVerbose) Log.v(TAG, "Library already added"); 69 return; 70 } 71 mLibraries.add(libraryPath); 72 // Chain another path loader to the current chain 73 mCurrentClassLoader = new PathClassLoader(libraryPath, mCurrentClassLoader); 74 } 75 } 76 77 public void addPackage(String packageName) { 78 if (mLogVerbose) Log.v(TAG, "Adding package " + packageName); 79 /* TODO: This should use a getPackage call in the caller's context, but no such method exists. 80 Package pkg = Package.getPackage(packageName); 81 if (pkg == null) { 82 throw new IllegalArgumentException("Unknown filter package '" + packageName + "'!"); 83 } 84 */ 85 mPackages.add(packageName); 86 } 87 88 public Filter createFilterByClassName(String className, String filterName) { 89 if (mLogVerbose) Log.v(TAG, "Looking up class " + className); 90 Class filterClass = null; 91 92 // Look for the class in the imported packages 93 for (String packageName : mPackages) { 94 try { 95 if (mLogVerbose) Log.v(TAG, "Trying "+packageName + "." + className); 96 synchronized(mClassLoaderGuard) { 97 filterClass = mCurrentClassLoader.loadClass(packageName + "." + className); 98 } 99 } catch (ClassNotFoundException e) { 100 continue; 101 } 102 // Exit loop if class was found. 103 if (filterClass != null) { 104 break; 105 } 106 } 107 if (filterClass == null) { 108 throw new IllegalArgumentException("Unknown filter class '" + className + "'!"); 109 } 110 return createFilterByClass(filterClass, filterName); 111 } 112 113 public Filter createFilterByClass(Class filterClass, String filterName) { 114 // Make sure this is a Filter subclass 115 try { 116 filterClass.asSubclass(Filter.class); 117 } catch (ClassCastException e) { 118 throw new IllegalArgumentException("Attempting to allocate class '" + filterClass 119 + "' which is not a subclass of Filter!"); 120 } 121 122 // Look for the correct constructor 123 Constructor filterConstructor = null; 124 try { 125 filterConstructor = filterClass.getConstructor(String.class); 126 } catch (NoSuchMethodException e) { 127 throw new IllegalArgumentException("The filter class '" + filterClass 128 + "' does not have a constructor of the form <init>(String name)!"); 129 } 130 131 // Construct the filter 132 Filter filter = null; 133 try { 134 filter = (Filter)filterConstructor.newInstance(filterName); 135 } catch (Throwable t) { 136 // Condition checked below 137 } 138 139 if (filter == null) { 140 throw new IllegalArgumentException("Could not construct the filter '" 141 + filterName + "'!"); 142 } 143 return filter; 144 } 145 } 146