View Javadoc

1   /*
2    * Copyright 2011 The Kuali Foundation
3    *
4    * Licensed under the the Educational Community License, Version 1.0
5    * (the "License"); you may not use this file except in compliance
6    * with the License.  You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl1.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13   * implied.  See the License for the specific language governing
14   * permissions and limitations under the License.
15   */
16  
17  package org.kuali.student.r2.common.dao;
18  
19  import java.lang.reflect.ParameterizedType;
20  import java.lang.reflect.Type;
21  import java.util.ArrayList;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.Set;
25  
26  import javax.persistence.EntityManager;
27  import javax.persistence.NoResultException;
28  import javax.persistence.NonUniqueResultException;
29  import javax.persistence.PersistenceContext;
30  import javax.persistence.Query;
31  
32  import org.apache.commons.lang.StringUtils;
33  import org.kuali.student.r2.common.entity.PersistableEntity;
34  import org.kuali.student.r2.common.exceptions.DoesNotExistException;
35  
36  /**
37   * @author Kuali Student Team
38   */
39  public class GenericEntityDao<T extends PersistableEntity<String>> implements EntityDao<String,T> {
40  
41      /**
42       * Entity class.
43       */
44      protected Class<T> entityClass;
45  
46      @PersistenceContext
47      protected EntityManager em;
48  
49      public GenericEntityDao() {
50          entityClass = getEntityClass();
51      }
52  
53      @Override
54      public T find(String primaryKey) {
55          return em.find(entityClass, primaryKey);
56      }
57  
58      @Override
59      public List<T> findByIds(String primaryKeyMemberName, List<String> primaryKeys) throws DoesNotExistException {
60      	
61  		// fix for jira KSENROLL-2949
62  		if (primaryKeys.isEmpty())
63  			return new ArrayList<T>();
64  		
65  		Set<String>primaryKeySet = new HashSet<String>(primaryKeys.size());
66  		// remove duplicates from the key list
67  		primaryKeySet.addAll(primaryKeys);
68  
69  		String queryString = "from " + entityClass.getSimpleName() + " where "
70  				+ primaryKeyMemberName + " in (:ids)";
71  		
72  		List<T> resultList = em.createQuery(queryString)
73  				.setParameter("ids", primaryKeySet).getResultList();
74  
75  		verifyResults(resultList, primaryKeySet);
76  
77  		return resultList;
78      }
79  
80      /**
81       * Check if an entity exists with the primary key given.
82       * 
83       * @param primaryKey the primary key identifier for the entity that will be checked.
84       * @return true if there is a row/entity with the primary key given in the database; false otherwise.
85       * 
86       */
87      public boolean entityExists (String primaryKey) {
88          
89          // TODO: see if this can be externalized as a named query.
90          Query q = em.createQuery("select id from " + entityClass.getSimpleName() + " where id = :key").setParameter("key", primaryKey);
91      
92          Object result;
93          try {
94              result = q.getSingleResult();
95          }
96          catch (NonUniqueResultException e) {
97              // more than 1 match (should never happen...)
98              return false;
99          } 
100         catch (NoResultException e) {
101             // zero matches
102             return false;
103         }
104 
105         // all other cases
106         return true;
107         
108     }
109     protected void verifyResults(List<T> resultList, Set<String> primaryKeys) throws DoesNotExistException {
110 
111     	 if (resultList.size() == 0)
112          	throw new DoesNotExistException("No data was found for : " + StringUtils.join(primaryKeys, ", "));
113     	 
114          else if (resultList.size() != primaryKeys.size()) {
115         	 // only found some of the keys given.
116          	Set<String> unmatchedKeySet = new HashSet<String> ();
117          
118          	unmatchedKeySet.addAll(primaryKeys);
119          	
120          	for (T t : resultList) {
121  				
122          		unmatchedKeySet.remove(t.getId());
123  			}
124          	
125          	throw new DoesNotExistException("Missing data for : " + StringUtils.join(unmatchedKeySet.iterator(), ", "));
126          	
127          }
128 	}
129 
130 	@Override
131     public List<T> findByIds(List<String> primaryKeys) throws DoesNotExistException {
132 
133         if(primaryKeys.size() >= 1000){
134             return this.findByIdsMaxKeys(primaryKeys);
135         } else {
136             return this.findByIds("id", primaryKeys); // faster but has a limit of 1000 in oracle 10g
137         }
138     }
139 
140     /**
141      * Use this method if the size of primary keys >= 1000. 1000 is the "in" limit for many databases.
142      *
143      * @param primaryKeys
144      * @return
145      * @throws DoesNotExistException
146      */
147     protected List<T> findByIdsMaxKeys(List<String> primaryKeys) throws DoesNotExistException {
148         List<T> resultList = new ArrayList<T>();
149 
150      // fix for jira KSENROLL-2949
151         if (primaryKeys.isEmpty())
152          	return new ArrayList<T>();
153         
154         Set<String>primaryKeySet = new HashSet<String>(primaryKeys.size());
155 		// remove duplicate keys
156 		primaryKeySet.addAll(primaryKeys);
157 
158         
159         for (String primaryKey : primaryKeys) {
160 
161             T entity = find(primaryKey);
162 
163             if (entity == null) {
164 
165                 throw new DoesNotExistException("No data was found for :" + primaryKey);
166 
167             }
168             resultList.add(entity);
169         }
170         
171         verifyResults (resultList, primaryKeySet);
172         
173         return resultList;
174     }
175 
176 
177     @Override
178     @SuppressWarnings("unchecked")
179     public List<T> findAll() {
180         return (List<T>) em.createQuery("from " + entityClass.getSimpleName()).getResultList();
181     }
182 
183     @Override
184     public void persist(T entity) {
185         em.persist(entity);
186     }
187 
188     @Override
189     public void update(T entity) {
190         em.merge(entity);
191     }
192 
193     @Override
194     public void remove(T entity) {
195         em.remove(entity);
196     }
197 
198     @Override
199     public T merge(T entity) {
200         
201         if (em.contains(entity))
202             em.detach(entity);
203         
204         return em.merge(entity);
205     }
206 
207     @SuppressWarnings("unchecked")
208     protected <C extends T> Class<C> getEntityClass() {
209         if (entityClass == null) {
210             entityClass = (Class<T>) getEntityType(this);
211         }
212         return (Class<C>) entityClass;
213     }
214 
215     private Type getEntityType(Object object) {
216         Type type = object.getClass().getGenericSuperclass();
217         if (type instanceof ParameterizedType) {
218             ParameterizedType paramType = (ParameterizedType) type;
219             Type result = paramType.getActualTypeArguments()[0];
220             return result;
221         } else {
222             throw new IllegalArgumentException("Could not guess entity type by reflection.");
223         }
224     }
225 
226     @Override
227     public void setEm(EntityManager em) {
228         this.em = em;
229     }
230 
231     @Override
232     public EntityManager getEm() {
233         return em;
234     }
235 
236 
237 }