View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2005 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  package ch.elca.el4j.util.objectwrapper.impl;
18  
19  import java.lang.annotation.Annotation;
20  import java.lang.reflect.InvocationTargetException;
21  import java.lang.reflect.Method;
22  import java.util.Collection;
23  import java.util.LinkedList;
24  import java.util.List;
25  import java.util.Locale;
26  
27  import javax.persistence.ManyToMany;
28  import javax.persistence.OneToMany;
29  import javax.persistence.OneToOne;
30  
31  import org.hibernate.EntityMode;
32  import org.hibernate.SessionFactory;
33  import org.hibernate.metadata.ClassMetadata;
34  import org.hibernate.type.Type;
35  
36  import ch.elca.el4j.util.objectwrapper.ObjectWrapperRTException;
37  import ch.elca.el4j.util.objectwrapper.interfaces.Linked;
38  
39  /**
40   * Hibernate annotation implementation of Linked.
41   *
42   * @svnLink $Revision: 3880 $;$Date: 2009-08-04 15:17:52 +0200 (Di, 04. Aug 2009) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/hibernate/src/main/java/ch/elca/el4j/util/objectwrapper/impl/LinkedHibernateImpl.java $
43   *
44   * @author David Bernhard (DBD)
45   */
46  public class LinkedHibernateImpl extends AbstractWrapper implements Linked {
47  
48  	/**
49  	 * Persistence annotations. These are used to search for inverse links.
50  	 */
51  	private static List<Class<?extends Annotation>> s_candidates
52  		= new LinkedList<Class<?extends Annotation>>();
53  	
54  	/**
55  	 * Initialize annotation candidates.
56  	 */
57  	static {
58  		s_candidates.add(OneToMany.class);
59  		s_candidates.add(OneToOne.class);
60  		s_candidates.add(ManyToMany.class);
61  	}
62  	
63  	/** The session factory as source of hibernate metadata. */
64  	private final SessionFactory m_sessionFactory;
65  
66  	/** The metadata object. */
67  	private ClassMetadata m_meta;
68  	
69  	/** The simple properties. */
70  	private List<String> m_simple;
71  	
72  	/** The collection properties. */
73  	private List<String> m_collections;
74  	
75  	/**
76  	 * Create the implementation.
77  	 * @param sessionFactory The session factory.
78  	 */
79  	public LinkedHibernateImpl(SessionFactory sessionFactory) {
80  		m_sessionFactory = sessionFactory;
81  	}
82  	
83  	/** {@inheritDoc} */
84  	@Override
85  	public void create() {
86  		m_meta = m_sessionFactory.getClassMetadata(m_target.getClass());
87  		if (m_meta == null) {
88  			throw new ObjectWrapperRTException("Failed to create hibernate metadata.");
89  		}
90  		m_simple = new LinkedList<String>();
91  		m_collections = new LinkedList<String>();
92  		
93  		for (String property : m_meta.getPropertyNames()) {
94  			if (isInverse(m_target.getClass(), property)) {
95  				continue;
96  			}
97  			
98  			Type type = m_meta.getPropertyType(property);
99  			if (type.isCollectionType()) {
100 				m_collections.add(property);
101 			} else if (type.isAssociationType()) {
102 				m_simple.add(property);
103 			}
104 		}
105 	}
106 	
107 	/**
108 	 * Whether a property is marked with a mapped-by annotation and hence
109 	 * represents an inverse association.
110 	 * @param cls The domain class.
111 	 * @param property The property name.
112 	 * @return <code>true</code> if the annotation is present.
113 	 */
114 	private boolean isInverse(Class<?> cls, String property) {
115 		// Find the getter.
116 		String methodName = "get" + property.substring(0, 1)
117 			.toUpperCase(Locale.getDefault()) + property.substring(1);
118 		Method method;
119 		try {
120 			method = cls.getMethod(methodName);
121 		} catch (NoSuchMethodException e) {
122 			try {
123 				methodName = "is" + methodName.substring("get".length());
124 				method = cls.getMethod(methodName);
125 			} catch (NoSuchMethodException ex) {
126 				throw new ObjectWrapperRTException("No getter for " + property
127 					+ " in " + cls, ex);
128 			}
129 		} 
130 		
131 		// Get the annotations on the getter.
132 		boolean inverse = false;
133 	
134 	OUTER: 
135 		for (Annotation a : method.getAnnotations()) {
136 			for (Class<? extends Annotation> candidate : s_candidates) {
137 				if (candidate.isAssignableFrom(a.getClass()) 
138 					&& isInverseAnnotation(a)) {
139 					inverse = true;
140 					break OUTER;
141 				}
142 			}
143 		}
144 		
145 		return inverse;
146 	}
147 	
148 	/**
149 	 * Check if an annotation represents an inverse link.
150 	 * @param ann The annotaion.
151 	 * @return <code>true</code> if <code>mappedBy</code> was found and
152 	 * not empty.
153 	 */
154 	private boolean isInverseAnnotation(Annotation ann) {
155 		String str;
156 		try {
157 			Method mappedBy = ann.getClass().getMethod("mappedBy");
158 			str = (String) mappedBy.invoke(ann);
159 		} catch (NoSuchMethodException e) {
160 			throw new ObjectWrapperRTException("Missing mappedBy in " + ann, e);
161 		} catch (IllegalAccessException e) {
162 			throw new ObjectWrapperRTException(e);
163 		} catch (InvocationTargetException e) {
164 			throw new ObjectWrapperRTException(e);
165 		} 
166 		return !"".equals(str);
167 	}
168 
169 	/** {@inheritDoc} */
170 	public Object[] getAllLinked() {
171 		List<Object> objects = new LinkedList<Object>();
172 		for (String simple : m_simple) {
173 			Object obj = getlinkByName(simple);
174 			if (obj != null) {
175 				objects.add(obj);
176 			}
177 		}
178 		for (String collectionName : m_collections) {
179 			Collection<?> collection = getCollectionLinkByName(collectionName);
180 			for (Object obj : collection) {
181 				if (obj != null) {
182 					objects.add(obj);
183 				}
184 			}
185 		}
186 		return objects.toArray();
187 	}
188 
189 	/** {@inheritDoc} */
190 	public Collection<?> getCollectionLinkByName(String name) {
191 		return (Collection<?>) m_meta.getPropertyValue(m_target, name, EntityMode.POJO);
192 	}
193 
194 	/** {@inheritDoc} */
195 	public String[] getCollectionLinkNames() {
196 		return m_collections.toArray(new String[m_collections.size()]);
197 	}
198 
199 	/** {@inheritDoc} */
200 	public String[] getLinkNames() {
201 		return m_simple.toArray(new String[m_simple.size()]);
202 	}
203 
204 	/** {@inheritDoc} */
205 	public Object getlinkByName(String linkName) {
206 		return m_meta.getPropertyValue(m_target, linkName, EntityMode.POJO);
207 	}
208 }