Skip to main content
summaryrefslogtreecommitdiffstats
blob: 1004b65298f7de01da89ff40393550109fcd68b3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/**
 * <copyright>
 *
 * Copyright (c) 2005, 2006 Springsite BV (The Netherlands) and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Martin Taal
 *   Davide Marchignoli
 * </copyright>
 *
 * $Id: IdMapper.java,v 1.6 2006/11/15 17:17:52 mtaal Exp $
 */

package org.eclipse.emf.teneo.hibernate.mapper;

import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel;
import org.eclipse.emf.teneo.annotations.pannotation.EnumType;
import org.eclipse.emf.teneo.annotations.pannotation.GeneratedValue;
import org.eclipse.emf.teneo.annotations.pannotation.GenerationType;
import org.eclipse.emf.teneo.annotations.pannotation.SequenceGenerator;
import org.eclipse.emf.teneo.annotations.pannotation.TableGenerator;
import org.eclipse.emf.teneo.hibernate.hbannotation.GenericGenerator;
import org.eclipse.emf.teneo.hibernate.hbannotation.Parameter;
import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedEPackage;
import org.eclipse.emf.teneo.simpledom.DocumentHelper;
import org.eclipse.emf.teneo.simpledom.Element;

/**
 * Mapper generating id entry for Hibernate from PAnnotatedElements. Throws an error if called for non-root entities.
 * 
 * @author <a href="mailto:marchign at elver.org">Davide Marchignoli</a>
 * @author <a href="mailto:mtaal at elver.org">Martin Taal</a>
 */
class IdMapper extends AbstractPropertyMapper {

	/** The logger */
	private static final Log log = LogFactory.getLog(IdMapper.class);

	/** the hibernate generator class names */
	private static final String[] GENERATOR_CLASS_NAMES;

	/** initializes the hibernate class names array */
	static {
		GENERATOR_CLASS_NAMES = new String[GenerationType.VALUES.size()];
		GENERATOR_CLASS_NAMES[GenerationType.AUTO] = "native";
		GENERATOR_CLASS_NAMES[GenerationType.IDENTITY] = "identity";
		GENERATOR_CLASS_NAMES[GenerationType.SEQUENCE] = "sequence";
		GENERATOR_CLASS_NAMES[GenerationType.TABLE] = "hilo";
	}

	/** Util method to create an id or composite-id element */
	public static Element getCreateIdElement(Element entityElement, PAnnotatedEClass aClass) {
		if (aClass.getIdClass() != null) { // composite id
			Element element = entityElement.element("composite-id");
			if (element == null) {
				element = DocumentHelper.createElement("composite-id").addAttribute("class",
						aClass.getIdClass().getValue()).addAttribute("mapped", "true");
				entityElement.add(0, element);
			}
			return element;
		} else {
			Element element = entityElement.element("id");
			if (element == null) {
				element = DocumentHelper.createElement("id");
				entityElement.add(0, element);
			}
			return element;
		}
	}

	/**
	 * Add synthetic id to the class
	 */
	public static Element addSyntheticId(MappingContext mc, Element entityElement) {
		if (entityElement.element("id") != null || entityElement.element("composite-id") != null) {
			throw new MappingException("Syntheticid should only be called if there is no id element");
		}

		final Element idElement = DocumentHelper.createElement("id");
		entityElement.add(0, idElement);
		idElement.addAttribute("type", "long").
		// NOTE: the name is also set so that the property name can be
				// used later to identify an id prop,
				// TODO: improve this
				addAttribute("name", mc.getIdColumnName()).addAttribute("column", mc.getIdColumnName()).addElement(
						"generator").addAttribute("class", "native");

		final Element meta = new Element("meta");
		meta.addAttribute("attribute", HbMapperConstants.ID_META).addText("true");
		idElement.add(0, meta);

		idElement.addAttribute("access", mc.getIdPropertyHandlerName());

		return idElement;
	}

	/**
	 * @param hbmContext
	 */
	public IdMapper(MappingContext hbmContext) {
		super(hbmContext);
	}

	/**
	 * @return Returns the hibernate generator class for the given strategy.
	 */
	private static String hbGeneratorClass(GenerationType strategy) {
		return IdMapper.GENERATOR_CLASS_NAMES[strategy != null ? strategy.getValue() : GenerationType.AUTO];
	}

	/**
	 * Process embedded id.
	 */
	public void processEmbeddedId(PAnnotatedEReference aReference) {
		final EReference eReference = aReference.getAnnotatedEReference();
		final PAnnotatedEClass aClass = aReference.getPaModel().getPAnnotated(eReference.getEReferenceType());
		final Element compositeIdElement = getHbmContext().getCurrent().addElement("composite-id");
		compositeIdElement.addAttribute("name", eReference.getName());
		final String className = getHbmContext().getInstanceClassName(aClass.getPaModel(), aClass.getAnnotatedEClass());
		compositeIdElement.addAttribute("class", className);
		getHbmContext().setCurrent(compositeIdElement);
		final List aFeatures = aClass.getPaEStructuralFeatures();
		for (Iterator iter = aFeatures.iterator(); iter.hasNext();) {
			PAnnotatedEStructuralFeature aFeature = (PAnnotatedEStructuralFeature) iter.next();
			if (!(aFeature instanceof PAnnotatedEAttribute)) {
				continue;
			}
			PAnnotatedEAttribute aAttribute = (PAnnotatedEAttribute) aFeature;
			final Element keyPropertyElement = compositeIdElement.addElement("key-property");
			keyPropertyElement.addAttribute("name", aFeature.getAnnotatedEStructuralFeature().getName());
			addColumns(keyPropertyElement, aAttribute.getAnnotatedEAttribute().getName(), getColumns(aAttribute),
					getHbmContext().isCurrentElementFeatureMap(), false);
			setType(aAttribute, keyPropertyElement);
		}
		getHbmContext().setCurrent(compositeIdElement.getParent());
	}

	/**
	 * Add property to the mapped id element
	 */
	public void processIdProperty(PAnnotatedEAttribute id) {
		final PAnnotatedEClass aClass = id.getPaEClass();

		// check precondition
		if (aClass.getPaSuperEntity() != null && aClass.getPaSuperEntity().hasIdAnnotatedFeature()) {
			log
					.error("The annotated eclass: "
							+ aClass
							+ " has an id-annotated feature: "
							+ id
							+ " while it has a "
							+ "superclass/type, id properties should always be specified in the top of the inheritance structure");
			throw new MappingException(
					"The annotated eclass: "
							+ aClass
							+ " has an id-annotated feature: "
							+ id
							+ " while it has a "
							+ "superclass/type, id properties should always be specified in the top of the inheritance structure");
		}

		final EAttribute eAttribute = id.getAnnotatedEAttribute();
		final List columns = getColumns(id);
		final GeneratedValue generatedValue = id.getGeneratedValue();

		// if (column != null && column.getColumnDefinition() != null) {
		// // TODO support
		// log.error("Unsupported, ColumnDefinition in " + column);
		// throw new MappingException("Unsupported, ColumnDefinition", column);
		// }
		// if (column != null && column.getTable() != null) {
		// // TODO support
		// log.error("Unsupported, SecondaryTable in " + column);
		// throw new MappingException("Unsupported, SecondaryTable", column);
		// }

		final Element idElement = getCreateIdElement(getHbmContext().getCurrent(), aClass);
		final boolean isCompositeId = aClass.getIdClass() != null;

		final Element usedIdElement;
		if (isCompositeId) {
			usedIdElement = idElement.addElement("key-property");
		} else {
			usedIdElement = idElement;
		}

		addColumns(usedIdElement, eAttribute.getName(), columns, false, false);

		usedIdElement.addAttribute("name", eAttribute.getName());
		if (id.getEnumerated() == null) {
			setType(id, usedIdElement);
		} else { // enumerated id
			if (getHbmContext().isEasyEMFGenerated(id.getAnnotatedEAttribute().getEType())) {
				// if the instanceclass is registered in the context then this java class is
				// created differently
				final String typeName;
				if (EnumType.STRING == id.getEnumerated().getValue().getValue()) {
					typeName = "org.elver.persistence.hibernate.type.EnumUserType";
				} else {
					typeName = "org.elver.persistence.hibernate.type.EnumIntegerUserType";
				}

				final Class instanceClass = getHbmContext().getImpl(id.getAnnotatedEAttribute().getEType());
				usedIdElement.addElement("type").addAttribute("name", typeName).addElement("param").addAttribute(
						"name", "enumClassName").addText(instanceClass.getName());
			} else if (getHbmContext().isEasyEMFDynamic(id.getAnnotatedEAttribute().getEType())) {
				throw new UnsupportedOperationException("NOT YET SUPPORTED");
			} else if (id.getAnnotatedEAttribute().getEType().getInstanceClass() != null) {
				usedIdElement.addElement("type").addAttribute("name", getEnumUserType(id.getEnumerated())).addElement(
						"param").addAttribute("name", HbMapperConstants.ENUM_CLASS_PARAM).addText(
						eAttribute.getEType().getInstanceClass().getName());
			} else {
				final Element typeElement = usedIdElement.addElement("type").addAttribute("name",
						hbDynamicEnumType(id.getEnumerated()));
				typeElement.addElement("param").addAttribute("name", HbMapperConstants.ECLASSIFIER_PARAM).addText(
						id.getAnnotatedEAttribute().getEType().getName());
				typeElement.addElement("param").addAttribute("name", HbMapperConstants.EPACKAGE_PARAM).addText(
						id.getAnnotatedEAttribute().getEType().getEPackage().getNsURI());
			}
		}

		// TODO define what to do for unsettable id attribute (unlikely, maybe
		// error)

		if (generatedValue != null) {

			if (isCompositeId) {
				throw new MappingException("Composite id can not have a generated value "
						+ id.getAnnotatedEAttribute().getEContainingClass().getName() + "/"
						+ id.getAnnotatedEAttribute().getName());
			}

			final Element generatorElement = usedIdElement.addElement("generator");

			GenericGenerator gg;
			if (generatedValue.getGenerator() != null
					&& (gg = getGenericGenerator(id.getPaModel(), generatedValue.getGenerator())) != null) {
				log.debug("GenericGenerator the strategy in the GeneratedValue is ignored (if even set)");
				generatorElement.addAttribute("class", gg.getStrategy());
				if (gg.getParameters() != null) {
					for (Iterator params = gg.getParameters().iterator(); params.hasNext();) {
						final Parameter param = (Parameter) params.next();
						generatorElement.addElement("param").addAttribute("name", param.getName()).addText(
								param.getValue());
					}
				}
			} else if (GenerationType.IDENTITY_LITERAL.equals(generatedValue.getStrategy())) {
				generatorElement.addAttribute("class", "identity");
			} else if (GenerationType.TABLE_LITERAL.equals(generatedValue.getStrategy())) {
				generatorElement.addAttribute("class", IdMapper.hbGeneratorClass(generatedValue.getStrategy()));
				if (generatedValue.getGenerator() != null) { // table generator
					final TableGenerator tg = id.getPaModel().getTableGenerator(id.getAnnotatedEAttribute(),
							generatedValue.getGenerator());
					generatorElement.addElement("param").addAttribute("name", "table").setText(
							(tg.getTable() != null ? tg.getTable() : "uid_table")); // externalize
					generatorElement.addElement("param").addAttribute("name", "column").setText(
							tg.getValueColumnName() != null ? tg.getValueColumnName() : "next_hi_value_column"); // externalize
					generatorElement.addElement("param").addAttribute("name", "max_lo").setText(
							tg.getInitialValue() + "");
				} else {
					generatorElement.addElement("param").addAttribute("name", "table").setText("uid_table"); // externalize
					generatorElement.addElement("param").addAttribute("name", "column").setText("next_hi_value_column"); // externalize
				}
			} else if (GenerationType.SEQUENCE_LITERAL.equals(generatedValue.getStrategy())) {
				generatorElement.addAttribute("class", IdMapper.hbGeneratorClass(generatedValue.getStrategy()));
				if (generatedValue.getGenerator() != null) {
					final SequenceGenerator sg = id.getPaModel().getSequenceGenerator(id.getAnnotatedEAttribute(),
							generatedValue.getGenerator());
					generatorElement.addElement("param").addAttribute("name", "sequence").setText(sg.getSequenceName());
				}
			} else {
				generatorElement.addAttribute("class", IdMapper.hbGeneratorClass(generatedValue.getStrategy()));
			}
		}
	}

	/**
	 * Returns a sequence generator on the basis of its name, if not found then an exception is thrown. efeature is
	 * passed for debugging purposes.
	 */
	public GenericGenerator getGenericGenerator(PAnnotatedModel paModel, String name) {
		for (Iterator it = paModel.getPaEPackages().iterator(); it.hasNext();) {
			final HbAnnotatedEPackage pae = (HbAnnotatedEPackage) it.next();
			for (Iterator sit = pae.getHbGenericGenerators().iterator(); sit.hasNext();) {
				final GenericGenerator gg = (GenericGenerator) sit.next();
				if (gg.getName() != null && gg.getName().compareTo(name) == 0) {
					if (gg.getStrategy() == null) {
						throw new MappingException("The GenericGenerator: " + name + " has no strategy defined!");
					}

					return gg;
				}
			}
		}
		log.debug("No GenericGenerator defined under name: " + name);
		return null;
	}
}

Back to the top