/******************************************************************************* * Copyright (c) 2010 Robert "Unlogic" Olofsson (unlogic@unlogic.se). * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v3 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl-3.0-standalone.html ******************************************************************************/ package se.unlogic.standardutils.dao; import se.unlogic.standardutils.dao.annotations.DAOManaged; import se.unlogic.standardutils.dao.annotations.ManyToOne; import se.unlogic.standardutils.reflection.ReflectionUtils; import java.lang.reflect.Field; import java.sql.Connection; import java.sql.SQLException; import java.util.List; public class DefaultOneToManyRelation<LocalType,RemoteType> implements OneToManyRelation<LocalType, RemoteType> { private final Field field; private Field remoteField; private final AnnotatedDAOFactory daoFactory; private AnnotatedDAO<RemoteType> annotatedDAO; private QueryParameterFactory<RemoteType, LocalType> queryParameterFactory; private final Class<LocalType> beanClass; private final Class<RemoteType> remoteClass; private boolean initialized; public DefaultOneToManyRelation(Class<LocalType> beanClass, Class<RemoteType> remoteClass, Field field, AnnotatedDAOFactory daoFactory, DAOManaged daoManaged) { super(); this.beanClass = beanClass; this.remoteClass = remoteClass; this.field = field; this.daoFactory = daoFactory; List<Field> fields = ReflectionUtils.getFields(remoteClass); for(Field remoteField : fields){ if(remoteField.getType().equals(beanClass) && remoteField.isAnnotationPresent(DAOManaged.class) && remoteField.isAnnotationPresent(ManyToOne.class)){ this.remoteField = remoteField; ReflectionUtils.fixFieldAccess(this.remoteField); break; } } if(this.remoteField == null){ throw new RuntimeException("Unable to to find corresponding @ManyToOne field in class " + remoteClass + " for @OneToMany annotated field " + field.getName() + " in " + beanClass); } } /* (non-Javadoc) * @see se.unlogic.utils.dao.OneToManyRelation#setValue(LocalType, java.sql.Connection, java.lang.reflect.Field[]) */ public void getRemoteValue(LocalType bean, Connection connection, RelationQuery relationQuery) throws SQLException{ if(!initialized){ init(); } try { HighLevelQuery<RemoteType> query = new HighLevelQuery<RemoteType>(); query.addRelations(relationQuery); if(relationQuery != null){ query.disableAutoRelations(relationQuery.isDisableAutoRelations()); } query.addParameter(queryParameterFactory.getParameter(bean)); field.set(bean, annotatedDAO.getAll(query, connection)); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /* (non-Javadoc) * @see se.unlogic.utils.dao.OneToManyRelation#add(LocalType, java.sql.Connection, java.lang.reflect.Field[]) */ @SuppressWarnings("unchecked") public void add(LocalType bean, Connection connection, RelationQuery relationQuery) throws SQLException{ if(!initialized){ init(); } try { List<RemoteType> remoteBeans = (List<RemoteType>) field.get(bean); if(remoteBeans != null){ this.fixReferences(remoteBeans, bean); annotatedDAO.addAll(remoteBeans, connection, relationQuery); } } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } private void fixReferences(List<RemoteType> remoteBeans, LocalType bean) throws IllegalArgumentException, IllegalAccessException { for(RemoteType remoteBean : remoteBeans){ remoteField.set(remoteBean, bean); } } /* (non-Javadoc) * @see se.unlogic.utils.dao.OneToManyRelation#update(LocalType, java.sql.Connection, java.lang.reflect.Field[]) */ @SuppressWarnings("unchecked") public void update(LocalType bean, Connection connection, RelationQuery relationQuery) throws SQLException{ if(!initialized){ init(); } try { List<RemoteType> remoteBeans = (List<RemoteType>) field.get(bean); if(remoteBeans == null || remoteBeans.isEmpty()){ HighLevelQuery<RemoteType> query = new HighLevelQuery<RemoteType>(); query.addRelations(relationQuery); if(relationQuery != null){ query.disableAutoRelations(relationQuery.isDisableAutoRelations()); } query.addParameter(queryParameterFactory.getParameter(bean)); annotatedDAO.delete(query, connection); }else{ this.fixReferences(remoteBeans, bean); //TODO exclude current parameter QueryParameter<RemoteType,LocalType> queryParameter = queryParameterFactory.getParameter(bean); if(!annotatedDAO.deleteWhereNotIn(remoteBeans, connection, this.remoteField, queryParameter)){ HighLevelQuery<RemoteType> query = new HighLevelQuery<RemoteType>(); query.addParameter(queryParameter); annotatedDAO.delete(query, connection); } annotatedDAO.addOrUpdateAll(remoteBeans, connection, relationQuery); } } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } private void init() { if(annotatedDAO == null){ annotatedDAO = this.daoFactory.getDAO(remoteClass); queryParameterFactory = annotatedDAO.getParamFactory(remoteField, beanClass); } this.initialized = true; } public static <LT,RT> OneToManyRelation<LT, RT> getGenericInstance(Class<LT> beanClass, Class<RT> remoteClass, Field field, AnnotatedDAOFactory daoFactory, DAOManaged daoManaged){ return new DefaultOneToManyRelation<LT,RT>(beanClass,remoteClass,field,daoFactory,daoManaged); } }