/* * This code is distributed under The GNU Lesser General Public License (LGPLv3) * Please visit GNU site for LGPLv3 http://www.gnu.org/copyleft/lesser.html * * Copyright Denis Pavlov 2009 * Web: http://www.genericdtoassembler.org * SVN: https://svn.code.sf.net/p/geda-genericdto/code/trunk/ * SVN (mirror): http://geda-genericdto.googlecode.com/svn/trunk/ */ package com.inspiresoftware.lib.dto.geda.assembler; import com.inspiresoftware.lib.dto.geda.adapter.BeanFactory; import com.inspiresoftware.lib.dto.geda.adapter.DtoToEntityMatcher; import com.inspiresoftware.lib.dto.geda.exception.*; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * Collection/Map pipe meta contains information on the metadata of the pipe. * * @author DPavlov */ @SuppressWarnings("unchecked") public class MapPipeMetadata extends BasePipeMetadata implements com.inspiresoftware.lib.dto.geda.assembler.meta.MapPipeMetadata { private static final Map<Class, DtoToEntityMatcher> CACHE = new HashMap<Class, DtoToEntityMatcher>(); private final Class< ? extends Collection> dtoMapClass; private final String dtoMapClassKey; private final Class< ? > entityMapOrCollectionClass; private final String entityMapOrCollectionClassKey; private final Class< ? > returnType; private final String returnTypeKey; private final String mapKeyForCollection; private final boolean entityMapKey; private final DtoToEntityMatcher dtoToEntityMatcher; private final String dtoToEntityMatcherKey; /** * * @param dtoFieldName key for accessing field on DTO object * @param entityFieldName key for accessing field on Entity bean * @param dtoBeanKey key for constructing DTO bean * @param entityBeanKey key for constructing Entity bean * @param readOnly read only marker (true then write to entity is omitted) * @param dtoMapClass the dto collection class for creating new collection instance * @param dtoMapClassKey key for dto map class fetched from beanFactory * @param entityMapOrCollectionClass the entity collection/map class for creating new collection/map instance * @param entityMapOrCollectionClassKey key for entity collection/map class fetched from beanFactory * @param returnType the generic type for entity collection/map item * @param returnTypeKey bean factory key for generic type for entity collection/map item * @param mapKeyForCollection property whose value will be used as key for dto map. * @param entityMapKey true if map key is entity object, false if map value is entity object. * @param dtoToEntityMatcherClass matcher for synchronising collections * @param dtoToEntityMatcherKey key of matcher in the converters map * @throws UnableToCreateInstanceException if unable to create item matcher */ public MapPipeMetadata(final String dtoFieldName, final String entityFieldName, final String dtoBeanKey, final String entityBeanKey, final boolean readOnly, final Class<? extends Collection> dtoMapClass, final String dtoMapClassKey, final Class<?> entityMapOrCollectionClass, final String entityMapOrCollectionClassKey, final Class<?> returnType, final String returnTypeKey, final String mapKeyForCollection, final boolean entityMapKey, final Class<? extends DtoToEntityMatcher> dtoToEntityMatcherClass, final String dtoToEntityMatcherKey) throws UnableToCreateInstanceException { super(dtoFieldName, entityFieldName, dtoBeanKey, entityBeanKey, readOnly); this.dtoMapClass = dtoMapClass; this.returnTypeKey = returnTypeKey != null && returnTypeKey.length() > 0 ? returnTypeKey : null; this.dtoMapClassKey = dtoMapClassKey != null && dtoMapClassKey.length() > 0 ? dtoMapClassKey : null; this.entityMapOrCollectionClass = entityMapOrCollectionClass; this.entityMapOrCollectionClassKey = entityMapOrCollectionClassKey != null && entityMapOrCollectionClassKey.length() > 0 ? entityMapOrCollectionClassKey : null; this.returnType = returnType; this.mapKeyForCollection = mapKeyForCollection; this.entityMapKey = entityMapKey; if (dtoToEntityMatcherKey == null || dtoToEntityMatcherKey.length() == 0) { if (CACHE.containsKey(dtoToEntityMatcherClass)) { this.dtoToEntityMatcher = CACHE.get(dtoToEntityMatcherClass); } else { this.dtoToEntityMatcher = newBeanForClass( dtoToEntityMatcherClass, "Unable to create matcher: {0} for: {1} - {2}", dtoToEntityMatcherClass, this.getDtoBeanKey(), this.getEntityBeanKey()); CACHE.put(dtoToEntityMatcherClass, this.dtoToEntityMatcher); } this.dtoToEntityMatcherKey = null; } else { this.dtoToEntityMatcher = null; this.dtoToEntityMatcherKey = dtoToEntityMatcherKey; } } /** {@inheritDoc} */ public Map newDtoMap(final BeanFactory beanFactory) throws UnableToCreateInstanceException, BeanFactoryNotFoundException { if (this.dtoMapClassKey != null) { return newCollection(this.dtoMapClassKey, beanFactory, true); } return newCollection(this.dtoMapClass, " Dto field: ", this.getDtoFieldName()); } /** {@inheritDoc} */ public Object newEntityMapOrCollection(final BeanFactory beanFactory) throws UnableToCreateInstanceException, BeanFactoryNotFoundException { if (this.entityMapOrCollectionClassKey != null) { return newCollection(this.entityMapOrCollectionClassKey, beanFactory, false); } return newCollection(this.entityMapOrCollectionClass, " Entity field: ", this.getEntityFieldName()); } /** {@inheritDoc} */ public Class< ? > getReturnType(BeanFactory beanFactory) throws BeanFactoryUnableToLocateRepresentationException, BeanFactoryNotFoundException { if (this.returnTypeKey == null) { return returnType; } return getRepresentation(this.returnTypeKey, beanFactory, false); } /** {@inheritDoc} */ public String getMapKeyForCollection() { return mapKeyForCollection; } /** {@inheritDoc} */ public boolean isEntityMapKey() { return entityMapKey; } /** {@inheritDoc} */ public DtoToEntityMatcher getDtoToEntityMatcher(final Map<String, Object> converters) throws DtoToEntityMatcherNotFoundException, NotDtoToEntityMatcherException { if (this.dtoToEntityMatcherKey == null) { return dtoToEntityMatcher; } if (converters == null) { throw new DtoToEntityMatcherNotFoundException(this.getDtoFieldName(), this.getEntityFieldName(), this.dtoToEntityMatcherKey); } final Object matcher = converters.get(this.dtoToEntityMatcherKey); if (matcher == null) { throw new DtoToEntityMatcherNotFoundException(this.getDtoFieldName(), this.getEntityFieldName(), this.dtoToEntityMatcherKey); } if (matcher instanceof DtoToEntityMatcher) { return (DtoToEntityMatcher) matcher; } throw new NotDtoToEntityMatcherException(this.getDtoFieldName(), this.getEntityFieldName(), this.dtoToEntityMatcherKey); } private <T> T newCollection(final String clazzKey, final BeanFactory beanFactory, final boolean isDto) throws UnableToCreateInstanceException, BeanFactoryNotFoundException { if (beanFactory == null) { throw new BeanFactoryNotFoundException(this.getDtoFieldName(), clazzKey, isDto); } final Object coll = beanFactory.get(clazzKey); if (coll instanceof Collection || coll instanceof Map) { return (T) coll; } throw new UnableToCreateInstanceException(clazzKey, (isDto ? " Map Dto" : " Collection/Map Entity") + " field: " + this.getDtoFieldName() + "@key:" + clazzKey + " (Check if beanFactory [" + beanFactory + "] returns a correct instance)", null); } private <T> T newCollection(final Class< ? > clazz, final String type, final String field) throws UnableToCreateInstanceException { return (T) newBeanForClass(clazz, "Unable to create collection: {0} for {1} {2}", clazz, type, field); } private <T> T newBeanForClass(final Class<T> clazz, final String errMsg, final Object ... msgParams) throws UnableToCreateInstanceException { try { return clazz.newInstance(); } catch (Exception iex) { throw new UnableToCreateInstanceException(clazz.getCanonicalName(), String.format(errMsg, msgParams), iex); } } }