All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.batoo.jpa.parser.impl.metadata.MetadataImpl Maven / Gradle / Ivy

/*
 * Copyright (c) 2012 - Batoo Software ve Consultancy Ltd.
 * 
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.batoo.jpa.parser.impl.metadata;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.AccessType;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import javax.persistence.PersistenceException;
import javax.persistence.spi.PersistenceUnitInfo;

import org.batoo.jpa.parser.MappingException;
import org.batoo.jpa.parser.impl.acl.BaseAnnotatedClassLocator;
import org.batoo.jpa.parser.impl.metadata.type.EmbeddableMetadataImpl;
import org.batoo.jpa.parser.impl.metadata.type.EntityMetadataImpl;
import org.batoo.jpa.parser.impl.metadata.type.MappedSuperclassMetadataImpl;
import org.batoo.jpa.parser.metadata.EntityListenerMetadata;
import org.batoo.jpa.parser.metadata.Metadata;
import org.batoo.jpa.parser.metadata.NamedNativeQueryMetadata;
import org.batoo.jpa.parser.metadata.NamedQueryMetadata;
import org.batoo.jpa.parser.metadata.SequenceGeneratorMetadata;
import org.batoo.jpa.parser.metadata.SqlResultSetMappingMetadata;
import org.batoo.jpa.parser.metadata.TableGeneratorMetadata;
import org.batoo.jpa.parser.metadata.type.EmbeddableMetadata;
import org.batoo.jpa.parser.metadata.type.EntityMetadata;
import org.batoo.jpa.parser.metadata.type.ManagedTypeMetadata;
import org.batoo.jpa.parser.metadata.type.MappedSuperclassMetadata;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * Implementation of {@link Metadata}.
 * 
 * @author hceylan
 * @since 2.0.0
 */
public class MetadataImpl implements Metadata {

	private AccessType accessType;
	private boolean xmlMappingMetadataComplete;
	private String schema;
	private String catalog;

	private final List sequenceGenerators = Lists.newArrayList();
	private final List tableGenerators = Lists.newArrayList();

	private final List namedQueries = Lists.newArrayList();
	private final List namedNativeQueries = Lists.newArrayList();
	private final List sqlResultSetMappings = Lists.newArrayList();
	private final List entityListeners = Lists.newArrayList();
	private final Map entityMap = Maps.newHashMap();
	private boolean cascadePersist;

	/**
	 * 
	 * @since 2.0.0
	 */
	public MetadataImpl() {
		super();
	}

	/**
	 * @param classes
	 *            the explicit classes obtained from the Persistence XML
	 * 
	 * @since 2.0.0
	 */
	public MetadataImpl(List classes) {
		super();

		for (final String clazz : classes) {
			this.entityMap.put(clazz, null);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	@Override
	public boolean cascadePersists() {
		return this.cascadePersist;
	}

	/**
	 * Walks up the hierarchy to add the mapped super classes.
	 * 
	 * @param classloader
	 * @param entities
	 * @return
	 * 
	 * @since 2.0.1
	 */
	private ArrayList checkParentClasses(ClassLoader classloader, Set entities) {
		final ArrayList managedClasses = Lists.newArrayList(entities);

		for (final String className : entities) {
			try {
				Class clazz = classloader.loadClass(className);
				while (true) {
					clazz = clazz.getSuperclass();

					if ((clazz.getAnnotation(Entity.class) != null) || (clazz.getAnnotation(MappedSuperclass.class) != null)) {
						if (!managedClasses.contains(clazz.getName())) {
							managedClasses.add(clazz.getName());
						}
					}
					else {
						break;
					}
				}
			}
			catch (final ClassNotFoundException e) {
				throw new PersistenceException("Cannot load persistence class " + className + " referenced by orm mapping files");
			}
		}

		return managedClasses;
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	@Override
	public AccessType getAccessType() {
		return this.accessType;
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	@Override
	public String getCatalog() {
		return this.catalog;
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	@Override
	public List getEntityListeners() {
		return this.entityListeners;
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	@Override
	public List getEntityMappings() {
		return Lists.newArrayList(this.entityMap.values());
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	@Override
	public List getNamedNativeQueries() {
		return this.namedNativeQueries;
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	@Override
	public List getNamedQueries() {
		return this.namedQueries;
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	@Override
	public String getSchema() {
		return this.schema;
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	@Override
	public List getSequenceGenerators() {
		return this.sequenceGenerators;
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	@Override
	public List getSqlResultSetMapping() {
		return this.sqlResultSetMappings;
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	@Override
	public List getTableGenerators() {
		return this.tableGenerators;
	}

	/**
	 * {@inheritDoc}
	 * 
	 */
	@Override
	public boolean isXmlMappingMetadataComplete() {
		return this.xmlMappingMetadataComplete;
	}

	/**
	 * Merges the ORM XML based metadata.
	 * 
	 * @param metadata
	 *            the metadata to merge
	 * 
	 * @since 2.0.0
	 */
	public void merge(Metadata metadata) {
		this.accessType = metadata.getAccessType();
		this.catalog = metadata.getCatalog();
		this.schema = metadata.getSchema();

		this.xmlMappingMetadataComplete = metadata.isXmlMappingMetadataComplete();
		this.cascadePersist = metadata.cascadePersists();

		this.sequenceGenerators.addAll(metadata.getSequenceGenerators());
		this.tableGenerators.addAll(metadata.getTableGenerators());

		this.entityListeners.addAll(metadata.getEntityListeners());
		this.namedQueries.addAll(metadata.getNamedQueries());
		this.namedNativeQueries.addAll(metadata.getNamedNativeQueries());

		this.sqlResultSetMappings.addAll(metadata.getSqlResultSetMapping());

		for (final ManagedTypeMetadata managedType : metadata.getEntityMappings()) {
			final ManagedTypeMetadata existing = this.entityMap.put(managedType.getClassName(), managedType);

			if (existing != null) {
				throw new MappingException("Duplicate definitions for " + managedType.getClassName(), managedType.getLocator(), existing.getLocator());
			}
		}
	}

	/**
	 * Parses the types in the metamodel.
	 * 
	 * @param classloader
	 *            the class loader
	 * 
	 * @since 2.0.0
	 */
	public void parse(final ClassLoader classloader) {
		// sort the emanage classes by inheritence
		final ArrayList managedClasses = this.checkParentClasses(classloader, this.entityMap.keySet());

		Collections.sort(managedClasses, new Comparator() {

			@Override
			public int compare(String o1, String o2) {
				Class c1 = null, c2 = null;
				try {
					c1 = classloader.loadClass(o1);
				}
				catch (final ClassNotFoundException e) {
					throw new PersistenceException("Cannot load persistence class " + o1 + " referenced by orm mapping files");
				}

				try {
					c2 = classloader.loadClass(o2);
				}
				catch (final ClassNotFoundException e) {
					throw new PersistenceException("Cannot load persistence class " + o2 + " referenced by orm mapping files");
				}

				if (c1.isAssignableFrom(c2)) {
					return -1;
				}

				if (c2.isAssignableFrom(c1)) {
					return 1;
				}

				return 0;
			}
		});

		for (final String className : managedClasses) {
			final ManagedTypeMetadata metadata = this.entityMap.get(className);

			try {
				final Class clazz = classloader.loadClass(className);
				ManagedTypeMetadata parentMetadata = null;

				Class parentClass = clazz.getSuperclass();
				while ((parentMetadata == null) && (parentClass != Object.class)) {
					parentMetadata = this.entityMap.get(parentClass.getName());

					parentClass = parentClass.getSuperclass();
				}

				final AccessType parentAccessType = parentMetadata != null ? parentMetadata.getAccessType() : null;

				if (metadata == null) {
					if (clazz.getAnnotation(Entity.class) != null) {
						final EntityMetadataImpl entityMetadata = new EntityMetadataImpl(clazz, null, parentAccessType);
						this.entityMap.put(className, entityMetadata);

						this.namedQueries.addAll(entityMetadata.getNamedQueries());
						this.namedNativeQueries.addAll(entityMetadata.getNamedNativeQueries());
						this.sqlResultSetMappings.addAll(entityMetadata.getSqlResultSetMappings());
					}
					else if (clazz.getAnnotation(MappedSuperclass.class) != null) {
						this.entityMap.put(className, new MappedSuperclassMetadataImpl(clazz, (MappedSuperclassMetadata) metadata, parentAccessType));
					}
					else if (clazz.getAnnotation(Embeddable.class) != null) {
						this.entityMap.put(className, new EmbeddableMetadataImpl(clazz, (EmbeddableMetadata) metadata));
					}
					else {
						throw new MappingException("Cannot determine type of class " + className);
					}
				}
				else {
					if (metadata instanceof EntityMetadata) {
						this.entityMap.put(className, new EntityMetadataImpl(clazz, (EntityMetadata) metadata, parentAccessType));

						this.namedQueries.addAll(((EntityMetadata) metadata).getNamedQueries());
						this.namedNativeQueries.addAll(((EntityMetadata) metadata).getNamedNativeQueries());
						this.sqlResultSetMappings.addAll(((EntityMetadata) metadata).getSqlResultSetMappings());
					}
					else if (metadata instanceof MappedSuperclassMetadata) {
						this.entityMap.put(className, new MappedSuperclassMetadataImpl(clazz, (MappedSuperclassMetadata) metadata, parentAccessType));
					}
				}
			}
			catch (final ClassNotFoundException e) { // class could not be found
				throw new MappingException("Class " + className + " cound not be found.", metadata != null ? metadata.getLocator() : null);
			}
		}
	}

	/**
	 * Parses the types in the metamodel and in the jar files.
	 * 
	 * @param puInfo
	 *            the persistence unit info
	 * 
	 * @since 2.0.0
	 */
	public void parse(PersistenceUnitInfo puInfo) {
		final ClassLoader classloader = puInfo.getClassLoader();

		final Set> classes = BaseAnnotatedClassLocator.locatePersistentClasses(puInfo);

		for (final Class clazz : classes) {
			if (!this.entityMap.containsKey(clazz.getName()) && !this.entityMap.containsKey(clazz.getSimpleName())) {
				this.entityMap.put(clazz.getName(), null);
			}
		}

		this.parse(classloader);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy