package com.external.activeandroid; /* * Copyright (C) 2010 Michael Pardo * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import android.app.Application; import com.external.activeandroid.serializer.TypeSerializer; import com.external.activeandroid.util.Log; import com.external.activeandroid.util.ReflectionUtils; import dalvik.system.DexFile; final class ModelInfo { ////////////////////////////////////////////////////////////////////////////////////// // PRIVATE METHODS ////////////////////////////////////////////////////////////////////////////////////// private Map<Class<? extends Model>, TableInfo> mTableInfos; private Map<Class<?>, TypeSerializer> mTypeSerializers; ////////////////////////////////////////////////////////////////////////////////////// // CONSTRUCTORS ////////////////////////////////////////////////////////////////////////////////////// public ModelInfo(Application application) { mTableInfos = new HashMap<Class<? extends Model>, TableInfo>(); mTypeSerializers = new HashMap<Class<?>, TypeSerializer>(); try { scanForModel(application); } catch (IOException e) { Log.e("Couln't open source path.", e); } Log.i("ModelInfo loaded."); } ////////////////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////////////////// public Collection<TableInfo> getTableInfos() { return mTableInfos.values(); } public TableInfo getTableInfo(Class<? extends Model> type) { return mTableInfos.get(type); } @SuppressWarnings("unchecked") public List<Class<? extends Model>> getModelClasses() { return (List<Class<? extends Model>>) mTableInfos.keySet(); } public TypeSerializer getTypeSerializer(Class<?> type) { return mTypeSerializers.get(type); } ////////////////////////////////////////////////////////////////////////////////////// // PRIVATE METHODS ////////////////////////////////////////////////////////////////////////////////////// private void scanForModel(Application application) throws IOException { String packageName = application.getPackageName(); String sourcePath = application.getApplicationInfo().sourceDir; List<String> paths = new ArrayList<String>(); if (sourcePath != null) { DexFile dexfile = new DexFile(sourcePath); Enumeration<String> entries = dexfile.entries(); while (entries.hasMoreElements()) { paths.add(entries.nextElement()); } } // Robolectric fallback else { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Enumeration<URL> resources = classLoader.getResources(""); while (resources.hasMoreElements()) { String path = resources.nextElement().getFile(); if (path.contains("bin")) { paths.add(path); } } } for (String path : paths) { File file = new File(path); scanForModelClasses(file, packageName, application.getClass().getClassLoader()); } } private void scanForModelClasses(File path, String packageName, ClassLoader classLoader) { if (path.isDirectory()) { for (File file : path.listFiles()) { scanForModelClasses(file, packageName, classLoader); } } else { String className = path.getName(); // Robolectric fallback if (!path.getPath().equals(className)) { className = path.getPath(); if (className.endsWith(".class")) { className = className.substring(0, className.length() - 6); } else { return; } className = className.replace("/", "."); int packageNameIndex = className.lastIndexOf(packageName); if (packageNameIndex < 0) { return; } className = className.substring(packageNameIndex); } try { Class<?> discoveredClass = Class.forName(className, false, classLoader); if (ReflectionUtils.isModel(discoveredClass)) { @SuppressWarnings("unchecked") Class<? extends Model> modelClass = (Class<? extends Model>) discoveredClass; mTableInfos.put(modelClass, new TableInfo(modelClass)); } else if (ReflectionUtils.isTypeSerializer(discoveredClass)) { TypeSerializer typeSerializer = (TypeSerializer) discoveredClass.newInstance(); mTypeSerializers.put(typeSerializer.getDeserializedType(), typeSerializer); } } catch (ClassNotFoundException e) { Log.e("Couldn't create class.", e); } catch (InstantiationException e) { Log.e("Couldn't instantiate TypeSerializer.", e); } catch (IllegalAccessException e) { Log.e("IllegalAccessException", e); } } } }