/******************************************************************************* * Copyright (c) 2012 OpenLegacy Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * OpenLegacy Inc. - initial API and implementation *******************************************************************************/ package org.openlegacy.support; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openlegacy.EntitiesRegistry; import org.openlegacy.EntityDefinition; import org.openlegacy.loaders.ClassAnnotationsLoader; import org.openlegacy.loaders.FieldAnnotationsLoader; import org.openlegacy.loaders.FieldLoader; import org.openlegacy.loaders.RegistryLoader; import org.openlegacy.utils.TypesUtil; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils.FieldCallback; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; public class DefaultRegistryLoader<T> implements RegistryLoader { private final static Log logger = LogFactory.getLog(DefaultRegistryLoader.class); private Collection<FieldAnnotationsLoader> fieldAnnotationLoaders; private Collection<FieldLoader> fieldLoaders; private List<ClassAnnotationsLoader> classAnnotationLoaders; public void load(EntitiesRegistry<?, ?> entitiesRegistry) { entitiesRegistry.clear(); Assert.notNull(classAnnotationLoaders); Assert.notNull(fieldAnnotationLoaders); Assert.notNull(fieldLoaders); ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); Resource[] resources; List<String> packages = entitiesRegistry.getPackages(); if (packages == null) { logger.warn("Not packages defined for entity registry " + entitiesRegistry.getClass()); return; } for (String thePackage : packages) { try { String packagePath = org.openlegacy.utils.ClassUtils.packageToResourcePath(thePackage); resources = resourcePatternResolver.getResources("classpath*:" + packagePath + "/*.class"); // scan all classes with annotations for (Resource resource : resources) { Class<?> beanClass = getClassFromResource(packagePath, resource); loadSingleClass(entitiesRegistry, beanClass, false); } // another cycle on all classes for scanning fields of registered types (List<TableRowClass> for example) for (Resource resource : resources) { Class<?> beanClass = getClassFromResource(packagePath, resource); handleEntityFields(fieldLoaders, entitiesRegistry, beanClass); } } catch (Exception e) { throw (new RuntimeException(e)); } } fillEntitiesReferences(entitiesRegistry); } public void loadSingleClass(EntitiesRegistry<?, ?> entitiesRegistry, Class<?> beanClass, Boolean loadReferences) { if (org.openlegacy.utils.ClassUtils.isAbstract(beanClass)) { return; } if (entitiesRegistry.contains(beanClass)) { // class is reloaded - define the registry as dirty for designtime usage ((AbstractEntitiesRegistry<?, ?>)entitiesRegistry).setDirty(true); } Class<?> currentBeanClass = beanClass; // scan parent classes for annotations while (currentBeanClass != Object.class) { Annotation[] annotations = currentBeanClass.getAnnotations(); processAnnotations(classAnnotationLoaders, entitiesRegistry, beanClass, annotations); currentBeanClass = currentBeanClass.getSuperclass(); } // scan field for annotations handleEntityAnnotationFields(fieldAnnotationLoaders, entitiesRegistry, beanClass); handleEntityFields(fieldLoaders, entitiesRegistry, beanClass); if (loadReferences) { fillEntityReferences(entitiesRegistry, entitiesRegistry.get(beanClass)); } } public void setAnnotationLoaders(Collection<ClassAnnotationsLoader> classAnnotationLoaders) { this.classAnnotationLoaders = sortClassAnnoationLoaders(classAnnotationLoaders); } public void setFieldAnnotationLoaders(Collection<FieldAnnotationsLoader> fieldAnnotationLoaders) { this.fieldAnnotationLoaders = fieldAnnotationLoaders; } public void setFieldLoaders(Collection<FieldLoader> fieldLoaders) { this.fieldLoaders = fieldLoaders; } private static Class<?> getClassFromResource(String packagePath, Resource resource) throws IOException, ClassNotFoundException { String resourcePath = resource.getURI().toString(); String resourceRelativePath = resourcePath.substring(resourcePath.indexOf(packagePath), resourcePath.indexOf(".class")); String className = ClassUtils.convertResourcePathToClassName(resourceRelativePath); Class<?> beanClass = Class.forName(className); return beanClass; } /** * fills references to other entities * * @param entitiesRegistry */ private static void fillEntitiesReferences(final EntitiesRegistry<?, ?> entitiesRegistry) { @SuppressWarnings("unchecked") Collection<EntityDefinition<?>> entities = (Collection<EntityDefinition<?>>)entitiesRegistry.getEntitiesDefinitions(); for (final EntityDefinition<?> entityDefinition : entities) { fillEntityReferences(entitiesRegistry, entityDefinition); } } private static void fillEntityReferences(final EntitiesRegistry<?, ?> entitiesRegistry, final EntityDefinition<?> entityDefinition) { ReflectionUtils.doWithFields(entityDefinition.getEntityClass(), new FieldCallback() { public void doWith(Field field) { if (TypesUtil.isPrimitive(field.getType())) { return; } if (List.class.isAssignableFrom(field.getType())) { return; } EntityDefinition<?> childEntity = entitiesRegistry.get(field.getType()); if (childEntity != null) { entityDefinition.getChildEntitiesDefinitions().add(childEntity); } } }); } private static void processAnnotations(List<ClassAnnotationsLoader> annotationLoaders, EntitiesRegistry<?, ?> entitiesRegistry, Class<?> rootBeanClass, Annotation[] annotations) { for (ClassAnnotationsLoader annotationsLoader : annotationLoaders) { for (Annotation annotation : annotations) { if (annotationsLoader.match(annotation)) { if (logger.isDebugEnabled()) { logger.debug(MessageFormat.format("Loading annotation {0} for entity {1} into registry", annotation.annotationType().getSimpleName(), rootBeanClass)); } annotationsLoader.load(entitiesRegistry, annotation, rootBeanClass); } } } } private static List<ClassAnnotationsLoader> sortClassAnnoationLoaders( Collection<ClassAnnotationsLoader> annotationLoadersCollection) { List<ClassAnnotationsLoader> annotationLoaders = new ArrayList<ClassAnnotationsLoader>(annotationLoadersCollection); Collections.sort(annotationLoaders); return annotationLoaders; } private static List<FieldAnnotationsLoader> sortFieldAnnoationLoaders( Collection<FieldAnnotationsLoader> annotationLoadersCollection) { List<FieldAnnotationsLoader> annotationLoaders = new ArrayList<FieldAnnotationsLoader>(annotationLoadersCollection); Collections.sort(annotationLoaders); return annotationLoaders; } private static void handleEntityAnnotationFields(final Collection<FieldAnnotationsLoader> fieldAnnotationLoadersCollection, final EntitiesRegistry<?, ?> entitiesRegistry, final Class<?> beanClass) { final List<FieldAnnotationsLoader> fieldAnnotationLoaders = sortFieldAnnoationLoaders(fieldAnnotationLoadersCollection); ReflectionUtils.doWithFields(beanClass, new FieldCallback() { public void doWith(Field field) { loadDefinitionFromAnnotations(entitiesRegistry, beanClass, fieldAnnotationLoaders, field); } private void loadDefinitionFromAnnotations(final EntitiesRegistry<?, ?> entitiesRegistry, final Class<?> beanClass, final Collection<FieldAnnotationsLoader> fieldAnnotationLoaders, Field field) { Annotation[] annotations = field.getAnnotations(); for (FieldAnnotationsLoader fieldAnnotationsLoader : fieldAnnotationLoaders) { for (Annotation annotation : annotations) { if (fieldAnnotationsLoader.match(annotation)) { if (logger.isDebugEnabled()) { logger.debug(MessageFormat.format( "Loading annotation {0} for field {1} in entity {2} into registry", annotation.annotationType().getSimpleName(), field.getName(), beanClass)); } fieldAnnotationsLoader.load(entitiesRegistry, field, annotation, beanClass); } } } } }); } private static void handleEntityFields(final Collection<FieldLoader> fieldLoaders, final EntitiesRegistry<?, ?> entitiesRegistry, final Class<?> beanClass) { ReflectionUtils.doWithFields(beanClass, new FieldCallback() { public void doWith(Field field) { loadDefinition(entitiesRegistry, beanClass, fieldLoaders, field); } private void loadDefinition(final EntitiesRegistry<?, ?> entitiesRegistry, final Class<?> beanClass, final Collection<FieldLoader> fieldLoaders, Field field) { for (FieldLoader fieldLoader : fieldLoaders) { if (fieldLoader.match(entitiesRegistry, field)) { if (logger.isDebugEnabled()) { logger.debug(MessageFormat.format("Loading field {0} setting for entity {1} into registry", field.getName(), beanClass)); } fieldLoader.load(entitiesRegistry, field, beanClass); } } } }); } }