Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.jknack.mwa.jpa.JpaFixtures Maven / Gradle / Ivy
package com.github.jknack.mwa.jpa;
import static org.apache.commons.lang3.StringUtils.join;
import static org.apache.commons.lang3.Validate.notEmpty;
import static org.apache.commons.lang3.Validate.notNull;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.ejb.HibernateEntityManager;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.metadata.ClassMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.ResourceUtils;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.extensions.compactnotation.CompactConstructor;
import org.yaml.snakeyaml.extensions.compactnotation.CompactData;
import org.yaml.snakeyaml.nodes.ScalarNode;
/**
* Load a set of test files in JSON format.
*
* @author edgar.espina
*
*/
public final class JpaFixtures {
/**
* The logging system.
*/
private static final Logger logger = LoggerFactory.getLogger(JpaFixtures.class);
/**
* Not allowed.
*/
private JpaFixtures() {
}
/**
* Persist any entity found under the base directory.
*
* @param applicationContext The application's context. Required.
* @param emf The entity manager factory. Required.
* @param baseDir The base directory. Required.
* @param metadata The map with entities names and classes.
*/
public static void load(final ApplicationContext applicationContext,
final EntityManagerFactory emf, final String baseDir,
final Map metadata) {
notNull(applicationContext, "The application's context is required.");
notNull(emf, "The entity manager factory is required.");
notEmpty(baseDir, "The baseDir is required.");
notNull(metadata, "The classes are required.");
try {
// load models...
Iterable entities = load(applicationContext, metadata, baseDir);
for (Object entity : entities) {
EntityManager em = emf.createEntityManager();
SessionImplementor session = (SessionImplementor) ((HibernateEntityManager) em)
.getSession();
EntityTransaction trx = em.getTransaction();
boolean rollback = true;
try {
ClassMetadata cmetadata = metadata.get(entity.getClass().getName());
trx.begin();
Serializable id = cmetadata.getIdentifier(entity, session);
if (id == null) {
// Persist works if id generation is generated by database.
em.persist(entity);
} else {
// Find the entity under the given id.
Object existing = em.find(entity.getClass(), id);
if (existing == null) {
// doesn't exist, use merge and avoid detached instances error generated by persist.
em.merge(entity);
} else {
// It exists! force a failure and report the problem in the next catch statement.
em.persist(entity);
}
}
trx.commit();
rollback = false;
} catch (EntityExistsException ex) {
logger.warn("Entity exists: "
+ ToStringBuilder.reflectionToString(entity, ToStringStyle.MULTI_LINE_STYLE));
logger.debug("Entity exists: ", ex);
} catch (PersistenceException ex) {
// See https://hibernate.onjira.com/browse/HHH-4131
Throwable cause = ex.getCause();
if (cause != null && cause.getMessage().startsWith("detached")) {
logger.warn("Entity exists: "
+ ToStringBuilder.reflectionToString(entity, ToStringStyle.MULTI_LINE_STYLE));
logger.debug("Entity exists: ", ex);
} else {
throw ex;
}
} finally {
if (rollback && trx.isActive()) {
trx.rollback();
}
em.close();
}
}
} catch (Exception ex) {
throw new IllegalStateException("Unable to load fixtures", ex);
}
}
/**
* Load YAML files and parse them.
*
* @param applicationContext The application's context. Required.
* @param metadata Keys are entity's name, values are Java classes.
* @param baseDir It will be recursively scanned for .yml
files.
* @param Entity types.
* @return A set of objects
* @throws IOException If resources fail to read.
*/
@SuppressWarnings({"unchecked", "rawtypes" })
public static Iterable load(final ApplicationContext applicationContext,
final Map metadata, final String baseDir) throws IOException {
String pattern = new File(baseDir, "**/*.yml").toString().replace('\\', '/');
logger.debug("Searching for: {}", pattern);
Resource[] resources = getResources(applicationContext, pattern);
Yaml yaml = newYaml(applicationContext, metadata);
Set result = new LinkedHashSet();
for (Resource resource : resources) {
logger.debug(" yaml file found: {}", resource);
String yml = toString(resource);
Object root = yaml.load(yml);
if (root instanceof List) {
List objects = (List) root;
for (Object object : objects) {
result.add((T) object);
}
} else {
result.add((T) root);
}
}
return result;
}
/**
* Read resources list and fallback to classpath search if resources are not found.
*
* @param resolver A resource resolver.
* @param pattern The pattern to look for.
* @return A list of resources.
* @throws IOException If file location doesn't exist.
*/
private static Resource[] getResources(final ResourcePatternResolver resolver,
final String pattern) throws IOException {
Resource[] resources;
try {
resources = resolver.getResources(pattern);
} catch (FileNotFoundException ex) {
// Fallback to classpath
String fallbackPattern = ResourceUtils.CLASSPATH_URL_PREFIX + pattern;
logger.debug("Resources not found: {}, looking at: {}", pattern, fallbackPattern);
try {
resources = resolver.getResources(fallbackPattern);
} catch (FileNotFoundException iex) {
resources = new Resource[0];
}
}
Arrays.sort(resources, new Comparator() {
@Override
public int compare(final Resource r1, final Resource r2) {
String f1 = r1.getFilename();
String f2 = r2.getFilename();
return f1.compareToIgnoreCase(f2);
}
});
return resources;
}
/**
* Read the given resource as String.
*
* @param resource The resource.
* @return The resource content.
* @throws IOException If the resource content cannot be read it.
*/
private static String toString(final Resource resource) throws IOException {
InputStream in = null;
try {
in = resource.getInputStream();
return IOUtils.toString(in, "UTF-8");
} finally {
IOUtils.closeQuietly(in);
}
}
/**
* Creates a Yaml instance and register all the given class's name for using
* CompactObjectNotation.
*
* @param applicationContext The application's context.
* @param metadata Keys are entity's name, values are Java classes.
* @return A new Yaml instance.
*/
private static Yaml newYaml(final ApplicationContext applicationContext,
final Map metadata) {
CompactConstructor constructor = new CompactConstructor() {
@Override
protected Class> getClassForName(final String name) throws ClassNotFoundException {
Collection classes = metadata.values();
for (ClassMetadata classMetadata : classes) {
Class> mappedClass = classMetadata.getMappedClass();
if (name.equals(mappedClass.getSimpleName())) {
return mappedClass;
}
}
return super.getClassForName(name);
}
@Override
protected Object createInstance(final ScalarNode node, final CompactData data)
throws Exception {
Class> clazz = getClassForName(data.getPrefix());
Constructor>[] constructors = clazz.getDeclaredConstructors();
ConversionService conversionService = applicationContext.getBean(ConversionService.class);
// find best matching constructor
for (Constructor> constructor : constructors) {
Class>[] parameterTypes = constructor.getParameterTypes();
if (parameterTypes.length == data.getArguments().size()) {
boolean found = true;
int p = 0;
Object[] args = new Object[parameterTypes.length];
while (found && p < parameterTypes.length) {
Class> parameterType = parameterTypes[p];
boolean canConvert = conversionService.canConvert(String.class, parameterType);
if (canConvert) {
args[p] = conversionService.convert(data.getArguments().get(p), parameterType);
}
found &= canConvert;
p++;
}
if (found) {
constructor.setAccessible(true);
return BeanUtils.instantiateClass(constructor, args);
}
}
}
throw new IllegalArgumentException("Constructor not found: " + clazz.getName()
+ "(" + join(data.getArguments(), ",") + ")");
}
};
// Add !tag
for (Entry entry : metadata.entrySet()) {
ClassMetadata cmetadata = entry.getValue();
Class> mappedClass = cmetadata.getMappedClass();
String tag = "!!" + mappedClass.getSimpleName();
constructor.addTypeDescription(new TypeDescription(mappedClass, tag));
}
return new Yaml(constructor);
}
}