Java tutorial
/** * calipso-hub-framework - A full stack, high level framework for lazy application hackers. * Copyright 2005 Manos Batsis (manosbatsis gmail) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package gr.abiss.calipso.tiers.util; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.OneToOne; import org.apache.commons.lang.StringUtils; import org.hibernate.annotations.ManyToAny; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.core.GenericCollectionTypeResolver; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; import gr.abiss.calipso.tiers.annotation.ModelRelatedResource; import gr.abiss.calipso.tiers.annotation.ModelResource; /** * Adapter-ish context class for classes with {@link javax.persistence.ModelResource} * and {@link gr.abiss.calipso.tiers.annotation.ModelRelatedResource} * annotations. */ public final class ModelContext { private static final Logger LOGGER = LoggerFactory.getLogger(ModelContext.class); private Class<?> modelType; private Class<?> modelIdType; private final Class<?> parentClass; private final String name, path, parentProperty, generatedClassNamePrefix, beansBasePackage; private Class<?> repositoryType; private Class<?> serviceInterfaceType; private Class<?> serviceImplType; private AbstractBeanDefinition repositoryDefinition, serviceDefinition, controllerDefinition; private Map<String, Object> apiAnnotationMembers; private ModelResource modelResource; public List<Class<?>> getGenericTypes() { List<Class<?>> genericTypes = new LinkedList<Class<?>>(); genericTypes.add(this.getModelType()); genericTypes.add(this.getModelIdType()); return genericTypes; } public ModelContext(ModelResource modelResource, Class<?> domainClass) { Assert.notNull(domainClass, "A domain class is required"); String packageName = domainClass.getPackage().getName(); this.beansBasePackage = packageName.endsWith(".model") ? packageName.substring(0, packageName.indexOf(".model")) : packageName; this.modelType = (Class<?>) domainClass; this.modelResource = modelResource; this.name = getPath(domainClass); this.apiAnnotationMembers = getApiAnnotationMembers(domainClass); this.path = "/" + name; this.generatedClassNamePrefix = domainClass.getSimpleName().replace("Model", "").replace("Entity", ""); this.parentClass = null; this.parentProperty = null; this.modelIdType = EntityUtil.getIdType(domainClass); } public ModelContext(ModelRelatedResource resource, Class<?> domainClass) { String packageName = domainClass.getPackage().getName(); this.beansBasePackage = packageName.endsWith(".model") ? packageName.substring(0, packageName.indexOf(".model")) : packageName; this.name = getPath(domainClass); this.apiAnnotationMembers = getApiAnnotationMembers(domainClass); String parentProperty = resource.parentProperty(); this.parentClass = (Class<?>) ReflectionUtils.findField(domainClass, parentProperty).getType(); String parentName = getPath(parentClass); this.path = "/" + parentName + "/{peId}/" + this.name; this.modelType = (Class<?>) domainClass; this.modelIdType = EntityUtil.getIdType(domainClass); this.generatedClassNamePrefix = domainClass.getSimpleName().replace("Model", "").replace("Entity", ""); this.parentProperty = resource.parentProperty(); } public static ModelContext from(Class<?> domainClass) { ModelResource ar = domainClass.getAnnotation(ModelResource.class); ModelRelatedResource anr = domainClass.getAnnotation(ModelRelatedResource.class); ModelContext wrapper = null; if (ar != null) { wrapper = new ModelContext(ar, domainClass); } else if (anr != null) { wrapper = new ModelContext(anr, domainClass); } else { // look for an ancestor who might be a resource Class<?> superClass = domainClass.getSuperclass(); if (superClass != null && !Object.class.equals(superClass)) { wrapper = from(domainClass.getSuperclass()); } } wrapper.setModelType(domainClass); return wrapper; } private void setModelType(Class<?> modelType) { this.modelType = modelType; } public static ModelContext from(Field field) { Class<?> domainClass = field.getType(); if (Collection.class.isAssignableFrom(domainClass)) { domainClass = GenericCollectionTypeResolver.getCollectionFieldType(field); } return from(domainClass); }; public Class getControllerSuperClass() { return this.modelResource.controllerSuperClass(); } public Class<?> getServiceInterfaceType() { return serviceInterfaceType; } public void setServiceInterfaceType(Class<?> serviceInterfaceType) { this.serviceInterfaceType = serviceInterfaceType; } public Class<?> getServiceImplType() { return serviceImplType; } public void setServiceImplType(Class<?> serviceImplType) { this.serviceImplType = serviceImplType; } public Class<?> getRepositoryType() { return repositoryType; } public void setRepositoryType(Class<?> repositoryType) { this.repositoryType = repositoryType; } public boolean isNested() { return parentClass != null; } public String getGeneratedClassNamePrefix() { return generatedClassNamePrefix; } public boolean isNestedCollection() { if (!isNested()) { return false; } ModelRelatedResource anr = modelType.getAnnotation(ModelRelatedResource.class); Assert.notNull(anr, "Not a nested resource"); String parentProperty = anr.parentProperty(); Field field = ReflectionUtils.findField(modelType, parentProperty); if (hasAnnotation(field, OneToOne.class, org.hibernate.mapping.OneToOne.class)) { return false; } else if (hasAnnotation(field, ManyToOne.class, org.hibernate.mapping.ManyToOne.class, ManyToMany.class, ManyToAny.class)) { // TODO handle more mappings here? return true; } throw new IllegalStateException("No known mapping found"); } private boolean hasAnnotation(Field field, Class<?>... annotations) { for (Class<?> a : annotations) { if (field.isAnnotationPresent((Class<Annotation>) a)) { return true; } } return false; } public static String getPath(Class<?> domainClass) { ModelResource ar = domainClass.getAnnotation(ModelResource.class); ModelRelatedResource anr = domainClass.getAnnotation(ModelRelatedResource.class); String result; if (ar != null) { result = ar.path(); } else if (anr != null) { result = anr.path(); } else { throw new IllegalStateException("Not an entity"); } if (result == null || result.trim().isEmpty()) { result = domainClass.getSimpleName(); result = result.toLowerCase().charAt(0) + result.substring(1) + "s"; } return result; } public static Map<String, Object> getApiAnnotationMembers(Class<?> domainClass) { ModelResource resource = domainClass.getAnnotation(ModelResource.class); Map<String, Object> apiAnnotationMembers = new HashMap<String, Object>(); if (resource != null) { // get tags (grouping key, try API name) if (StringUtils.isNotBlank(resource.apiName())) { String[] tags = { resource.apiName() }; apiAnnotationMembers.put("tags", tags); } // or path else if (StringUtils.isNotBlank(resource.path())) { String[] tags = { resource.path() }; apiAnnotationMembers.put("tags", tags); } // or simple name else { String[] tags = { StringUtils .join(StringUtils.splitByCharacterTypeCamelCase(domainClass.getSimpleName()), ' ') }; apiAnnotationMembers.put("tags", tags); } // add description if (StringUtils.isNotBlank(resource.apiDescription())) { apiAnnotationMembers.put("description", resource.apiDescription()); } } else { throw new IllegalStateException("Not an entity"); } return apiAnnotationMembers.size() > 0 ? apiAnnotationMembers : null; } public Class<?> getModelIdType() { return modelIdType; } public Class<?> getModelType() { return modelType; } public String getName() { return name; } public String getPath() { return path; } public Map<String, Object> getApiAnnotationMembers() { return apiAnnotationMembers; } public String getParentProperty() { return parentProperty; } public AbstractBeanDefinition getRepositoryDefinition() { return repositoryDefinition; } public void setRepositoryDefinition(AbstractBeanDefinition repositoryDefinition) { this.repositoryDefinition = repositoryDefinition; } public AbstractBeanDefinition getServiceDefinition() { return serviceDefinition; } public void setServiceDefinition(AbstractBeanDefinition serviceDefinition) { this.serviceDefinition = serviceDefinition; } public AbstractBeanDefinition getControllerDefinition() { return controllerDefinition; } public void setControllerDefinition(AbstractBeanDefinition controllerDefinition) { this.controllerDefinition = controllerDefinition; } public String getBeansBasePackage() { return beansBasePackage; }; }