com.github.talberto.easybeans.atg.RepositoryBeanMapper Maven / Gradle / Ivy
The newest version!
/**
* Copyright 2014 Tomas Rodriguez
*
* 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.
*/
package com.github.talberto.easybeans.atg;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.objenesis.instantiator.ObjectInstantiator;
import org.objenesis.instantiator.basic.AccessibleInstantiator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import atg.beans.DynamicPropertyDescriptor;
import atg.nucleus.Nucleus;
import atg.repository.MutableRepository;
import atg.repository.MutableRepositoryItem;
import atg.repository.RepositoryException;
import atg.repository.RepositoryItem;
import atg.repository.RepositoryItemDescriptor;
import com.github.talberto.easybeans.api.MappingException;
import com.github.talberto.easybeans.api.RepositoryBean;
import com.github.talberto.easybeans.api.RepositoryId;
import com.github.talberto.easybeans.api.RepositoryProperty;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
/**
* Maps a RepositoryBean to a RepositoryItem and the other way around
*
* @author Tomas Rodriguez ([email protected])
*
*/
public class RepositoryBeanMapper {
protected final static Logger sLog = LoggerFactory.getLogger(RepositoryBeanMapper.class);
protected final static Predicate sNotRepositoryPropertyAnnotated = new Predicate() {
@Override
public boolean apply(PropertyDescriptor pPropertyDesc) {
Method reader = pPropertyDesc.getReadMethod();
Method writer = pPropertyDesc.getWriteMethod();
if(reader == null && writer == null) {
return false;
}
RepositoryProperty readerAnnotation = reader != null ? reader.getAnnotation(RepositoryProperty.class) : null;
RepositoryProperty writerAnnotation = writer != null ? writer.getAnnotation(RepositoryProperty.class) : null;
if(readerAnnotation == null && writerAnnotation == null) {
return false;
}
return true;
}
};
protected final static Predicate sRepositoryIdAnnotated = new Predicate() {
@Override
public boolean apply(PropertyDescriptor pDescriptor) {
Method reader = pDescriptor.getReadMethod();
Method writer = pDescriptor.getWriteMethod();
if(reader == null & writer == null) {
return false;
}
if(reader != null && reader.getAnnotation(RepositoryId.class) != null) {
return true;
} else if(writer != null && writer.getAnnotation(RepositoryId.class) != null) {
return true;
} else {
return false;
}
}
};
protected Logger mLog = LoggerFactory.getLogger(this.getClass());
/** Class of the mapped bean */
protected Class mType;
/** Repository where the repository items of type T
live */
protected MutableRepository mRepository;
/** Repository item descriptor */
protected RepositoryItemDescriptor mItemDescriptor;
protected Map mRepositoryDescForBeanPropertyName = Maps.newHashMap();
protected Map mRepositoryDescForRepositoryPropertyName = Maps.newHashMap();
/** Instantiator for the class T
*/
protected ObjectInstantiator mInstantiator;
/** Reference to the {@link NucleusEntityManager} */
protected NucleusEntityManager mEntityManager;
protected Nucleus mNucleus;
protected PropertyDescriptor mIdDescriptor;
public static RepositoryBeanMapper from(NucleusEntityManager pEntityManager, Class pType) {
sLog.trace("Entering from({})", pType);
return new RepositoryBeanMapper(pEntityManager, pType);
}
protected RepositoryBeanMapper(NucleusEntityManager pEntityManager, Class pType) {
mLog.trace("RepositoryBeanMapper.({}, {})", pEntityManager, pType);
mEntityManager = pEntityManager;
mType = pType;
mInstantiator = new AccessibleInstantiator(pType);
mLog.debug("Extracting metadata from class {}", pType);
RepositoryBean repositoryBeanAnnotation = mType.getAnnotation(RepositoryBean.class);
checkArgument(repositoryBeanAnnotation != null, "the type %s isn't annotated with @RepositoryBean", mType.getName());
String repositoryPath = repositoryBeanAnnotation.repository();
mRepository = (MutableRepository) getNucleus().resolveName(repositoryPath);
checkNotNull(mRepository, "Repository %s doesn't exist", repositoryPath);
String descriptorName = repositoryBeanAnnotation.descriptorName();
try {
mItemDescriptor = mRepository.getItemDescriptor(descriptorName);
} catch (RepositoryException e1) {
throw new IllegalArgumentException(String.format("Error building RepositoryBeanMapper for class [%s]", pType), e1);
}
mLog.debug("Metadata extracted for type [{}]: [repositoryPath=[{}], descriptorName=[{}]", pType, repositoryPath, descriptorName);
mLog.debug("Scanning method annotations");
BeanInfo beanInfo;
try {
beanInfo = Introspector.getBeanInfo(pType);
} catch (IntrospectionException e) {
throw new MappingException(String.format("Error extracting BeanInfo from %s", pType), e);
}
List descriptors = ImmutableList.copyOf(beanInfo.getPropertyDescriptors());
// Try to find the id property
Collection idDescriptors = Collections2.filter(descriptors, sRepositoryIdAnnotated);
if(idDescriptors.isEmpty()) {
throw new IllegalArgumentException(String.format("The type [%s] doesn't have any @RepositoryId annotated property", mType));
} else if(idDescriptors.size() > 1) {
throw new IllegalArgumentException(String.format("The type [%s] has more than one @RepositoryId annotated property", mType));
} else {
mIdDescriptor = idDescriptors.iterator().next();
}
// Remove descriptors that doesn't have any annotations neither on getter nor in setter
Collection repositoryPropertyDescriptors = Collections2.filter(descriptors, sNotRepositoryPropertyAnnotated);
if(repositoryPropertyDescriptors.isEmpty()) {
mLog.warn("The type [{}] doesn't have any @RepositoryProperty annotated property", mType);
}
for(PropertyDescriptor property : repositoryPropertyDescriptors) {
RepositoryPropertyMapper propertyMapper = RepositoryPropertyMapper.from(property);
mRepositoryDescForBeanPropertyName.put(property.getName(), propertyMapper);
mRepositoryDescForRepositoryPropertyName.put(propertyMapper.getRepositoryPropertyName(), propertyMapper);
}
}
protected Nucleus getNucleus() {
if(mNucleus == null) {
mNucleus = Nucleus.getGlobalNucleus();
}
return mNucleus;
}
public T find(Object pPk) {
mLog.trace("Entering find()");
try {
RepositoryItem item = mRepository.getItem(pPk.toString(), mItemDescriptor.getItemDescriptorName());
if(item == null) {
mLog.debug("Couldn't find any RepositoryItem with id [{}] in the repository [{}]. Returning null", pPk, mRepository);
return null;
} else {
mLog.debug("Found RepositoryItem [{}] for id [{}] in Repository [{}]. Converting it to a Bean of type [{}]", item, pPk, mRepository, mType);
return toBean(item);
}
} catch (RepositoryException e) {
throw new IllegalArgumentException();
}
}
public T toBean(RepositoryItem pItem) {
mLog.trace("Entering toBean({})", pItem);
mLog.debug("Creating new instance of type [{}]", mType);
@SuppressWarnings("unchecked")
T bean = (T) mInstantiator.newInstance();
mLog.debug("Extracting all properties from the RepositoryItem [{}]", pItem);
for(RepositoryPropertyMapper propertyMapper : mRepositoryDescForBeanPropertyName.values()) {
String repositoryPropertyName = propertyMapper.getRepositoryPropertyName();
mLog.debug("Mapping repository property [{}] to bean property [{}]", repositoryPropertyName, propertyMapper.getBeanPropertyName());
DynamicPropertyDescriptor propertyDescriptor;
try {
propertyDescriptor = pItem.getItemDescriptor().getPropertyDescriptor(repositoryPropertyName);
} catch (RepositoryException e) {
throw new IllegalArgumentException(e);
}
if(propertyDescriptor == null) {
throw new IllegalArgumentException(String.format("The property [%s] doesn't exist for the RepositoryItem [%s]", repositoryPropertyName, pItem));
}
Object repositoryPropertyValue;
if(propertyDescriptor.getPropertyType() == RepositoryItem.class) {
mLog.debug("Repository property is of type RepositoryItem, asking NucleusEntityManager to map this property");
RepositoryItem nestedItem = (RepositoryItem) pItem.getPropertyValue(repositoryPropertyName);
repositoryPropertyValue = mEntityManager.find(propertyMapper.getPropertyBeanType(), nestedItem.getRepositoryId());
} else {
repositoryPropertyValue = pItem.getPropertyValue(repositoryPropertyName);
}
mLog.debug("The value of the property is [{}], setting it in the bean", repositoryPropertyValue);
propertyMapper.setBeanProperty(bean, repositoryPropertyValue);
}
// Set the bean id
setBeanId(bean, pItem.getRepositoryId());
return bean;
}
public String create(T pItem) {
mLog.trace("Entering create({})", pItem);
MutableRepositoryItem repositoryItem;
try {
repositoryItem = mRepository.createItem(mItemDescriptor.getItemDescriptorName());
} catch (RepositoryException e) {
throw new MappingException(String.format("Exception creating RepositoryItem from bean [%s]", pItem), e);
}
mLog.debug("Created new RepositoryItem [{}]", repositoryItem);
mLog.debug("Extracting all properties from the Bean [{}]", pItem);
for(RepositoryPropertyMapper propertyMapper : mRepositoryDescForBeanPropertyName.values()) {
String repositoryPropertyName = propertyMapper.getRepositoryPropertyName();
String beanPropertyName = propertyMapper.getBeanPropertyName();
mLog.debug("Mapping repository property [{}] to bean property [{}]", repositoryPropertyName, beanPropertyName);
DynamicPropertyDescriptor propertyDescriptor;
try {
propertyDescriptor = repositoryItem.getItemDescriptor().getPropertyDescriptor(repositoryPropertyName);
} catch (RepositoryException e) {
throw new IllegalArgumentException(e);
}
if(propertyDescriptor == null) {
throw new IllegalArgumentException(String.format("The property [%s] doesn't exist for the RepositoryItem [%s]", repositoryPropertyName, pItem));
}
Object beanPropertyValue = propertyMapper.getBeanProperty(pItem, beanPropertyName);
if(propertyDescriptor.getPropertyType() == RepositoryItem.class) {
mLog.debug("Repository property is of type RepositoryItem, asking NucleusEntityManager to map this property");
String nestedRepositoryItemId = mEntityManager.create(beanPropertyValue);
// Assume the nested repository item belongs to the same repository
try {
RepositoryItem nestedRepositoryItem = mRepository.getItem(nestedRepositoryItemId, repositoryPropertyName);
repositoryItem.setPropertyValue(repositoryPropertyName, nestedRepositoryItem);
} catch (RepositoryException e) {
throw new MappingException(String.format("Error mapping bean property [%s] to repository property [%s]", beanPropertyName, repositoryPropertyName), e);
}
} else {
repositoryItem.setPropertyValue(repositoryPropertyName, beanPropertyValue);
}
}
// Update the repository with the newly created item
RepositoryItem finalRepositoryItem;
try {
finalRepositoryItem = mRepository.addItem(repositoryItem);
} catch (RepositoryException e) {
throw new MappingException(String.format("Error inserting new RepositoryItem [%s]", repositoryItem), e);
}
// Set the id of the bean
setBeanId(pItem, finalRepositoryItem.getRepositoryId());
return finalRepositoryItem.getRepositoryId();
}
protected void setBeanId(T pBean, String pId) {
try {
mIdDescriptor.getWriteMethod().invoke(pBean, pId);
} catch (Exception e) {
throw new MappingException(String.format("Error setting bean id [%s] of bean [%s]", pId, pBean), e);
}
}
protected String getBeanId(T pBean) {
try {
return (String) mIdDescriptor.getReadMethod().invoke(pBean);
} catch (Exception e) {
throw new MappingException(String.format("Error getting bean id of bean [%s]", pBean), e);
}
}
public RepositoryItem toRepositoryItem(MutableRepositoryItem pItem, T pBean) {
return null;
}
public void update(T pBean) {
mLog.trace("Entering update({})", pBean);
String repositoryId = getBeanId(pBean);
MutableRepositoryItem repositoryItem;
try {
repositoryItem = mRepository.getItemForUpdate(repositoryId, mItemDescriptor.getItemDescriptorName());
} catch (RepositoryException e) {
throw new MappingException(String.format("Exception updating RepositoryItem from bean [%s]", pBean), e);
}
mLog.debug("Got RepositoryItem for update[{}]", repositoryItem);
mLog.debug("Extracting all properties from the Bean [{}]", pBean);
for(RepositoryPropertyMapper propertyMapper : mRepositoryDescForBeanPropertyName.values()) {
String repositoryPropertyName = propertyMapper.getRepositoryPropertyName();
String beanPropertyName = propertyMapper.getBeanPropertyName();
mLog.debug("Mapping repository property [{}] to bean property [{}]", repositoryPropertyName, beanPropertyName);
DynamicPropertyDescriptor propertyDescriptor;
try {
propertyDescriptor = repositoryItem.getItemDescriptor().getPropertyDescriptor(repositoryPropertyName);
} catch (RepositoryException e) {
throw new IllegalArgumentException(e);
}
if(propertyDescriptor == null) {
throw new IllegalArgumentException(String.format("The property [%s] doesn't exist for the RepositoryItem [%s]", repositoryPropertyName, pBean));
}
Object beanPropertyValue = propertyMapper.getBeanProperty(pBean, beanPropertyName);
if(propertyDescriptor.getPropertyType() == RepositoryItem.class) {
mLog.debug("Repository property is of type RepositoryItem, asking NucleusEntityManager to map this property");
mEntityManager.update(beanPropertyValue);
} else {
repositoryItem.setPropertyValue(repositoryPropertyName, beanPropertyValue);
}
}
// Update the repository with the item
try {
mRepository.updateItem(repositoryItem);
} catch (RepositoryException e) {
throw new MappingException(String.format("Error inserting new RepositoryItem [%s]", repositoryItem), e);
}
}
public void delete(T pBean) {
mLog.trace("Entering update({})", pBean);
String repositoryId = getBeanId(pBean);
mLog.debug("Removing nested properties of the Bean [{}]", pBean);
for(RepositoryPropertyMapper propertyMapper : mRepositoryDescForBeanPropertyName.values()) {
String repositoryPropertyName = propertyMapper.getRepositoryPropertyName();
String beanPropertyName = propertyMapper.getBeanPropertyName();
mLog.debug("Mapping repository property [{}] to bean property [{}]", repositoryPropertyName, beanPropertyName);
DynamicPropertyDescriptor propertyDescriptor;
propertyDescriptor = mItemDescriptor.getPropertyDescriptor(repositoryPropertyName);
if(propertyDescriptor == null) {
throw new IllegalArgumentException(String.format("The property [%s] doesn't exist for the RepositoryItem [%s]", repositoryPropertyName, pBean));
}
if(propertyDescriptor.getPropertyType() == RepositoryItem.class) {
mLog.debug("Repository property is of type RepositoryItem, asking NucleusEntityManager to delete this property");
Object beanPropertyValue = propertyMapper.getBeanProperty(pBean, beanPropertyName);
mEntityManager.delete(beanPropertyValue);
}
}
mLog.debug("Deleting RepositoryItem [{}] of type [{}]", repositoryId, this.mItemDescriptor.getItemDescriptorName());
try {
mRepository.removeItem(repositoryId, this.mItemDescriptor.getItemDescriptorName());
} catch (RepositoryException e) {
throw new MappingException(String.format("Error removing item [%s] of type [%s] from Repository [%s]", repositoryId, this.mItemDescriptor.getItemDescriptorName(), mRepository), e);
}
}
/**
* @return the type
*/
public Class getType() {
return mType;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy