/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* 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:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.commons.test.db;
import com.google.common.io.Resources;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import com.google.inject.persist.jpa.JpaPersistModule;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.exceptions.ExceptionHandler;
import org.stringtemplate.v4.ST;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
* Helps to build persistence.xml for test purposes.
* If bound creates META-INF/persistence.xml with generated content.
*
* <p>The example of generated content is:
* <pre>{@code
* // for binding
* new PersistTestModuleBuilder().setDriver("org.h2.Driver")
* .addEntityClass(MyEntity.class)
* .addEntityClass(MyEntity2.class)
* .setUrl("jdbc:h2:mem:test")
* .setUser("username")
* .setPassword("secret")
* .build();
*
* // generated persistence.xml
* <persistence xmlns="http://java.sun.com/xml/ns/persistence"
* xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
* xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0">
* <persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
* <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
* <class>org.eclipse.che.module.MyEntity</class>
* <class>org.eclipse.che.module.MyEntity2</class>
* <properties>
* <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
* <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test"/>
* <property name="javax.persistence.jdbc.user" value="username"/>
* <property name="javax.persistence.jdbc.password" value="secret"/>
* </properties>
* </persistence-unit>
* </persistence>
* }</pre>
*
* @author Yevhenii Voevodin
*/
public class PersistTestModuleBuilder {
private static final String PERSISTENCE_XML_TEMPLATE_RESOURCE_PATH = "org/eclipse/che/commons/test/db/persistence.xml.template";
private final Map<String, String> properties = new LinkedHashMap<>();
private final Set<String> entityFqnSet = new LinkedHashSet<>();
private String persistenceUnit = "test";
/**
* Sets url, user and password equal to the values provided by server.
*/
public PersistTestModuleBuilder runningOn(DBTestServer server) {
setUrl(server.getUrl());
setUser(server.getUser());
setPassword(server.getPassword());
return this;
}
/**
* Sets the value of {@value PersistenceUnitProperties#JDBC_DRIVER} property.
*/
public PersistTestModuleBuilder setDriver(String driver) {
return setProperty(PersistenceUnitProperties.JDBC_DRIVER, driver);
}
/**
* Sets the value of {@value PersistenceUnitProperties#JDBC_DRIVER} property,
* the value would be equal to class fqn.
*/
public PersistTestModuleBuilder setDriver(Class<? extends java.sql.Driver> driverClass) {
return setDriver(driverClass.getName());
}
/**
* Sets the value of {@value PersistenceUnitProperties#JDBC_URL} property.
*/
public PersistTestModuleBuilder setUrl(String url) {
return setProperty(PersistenceUnitProperties.JDBC_URL, url);
}
/**
* Sets the value of {@value PersistenceUnitProperties#JDBC_USER} property.
*/
public PersistTestModuleBuilder setUser(String user) {
return setProperty(PersistenceUnitProperties.JDBC_USER, user);
}
/**
* Sets the value of {@value PersistenceUnitProperties#JDBC_PASSWORD} property.
*/
public PersistTestModuleBuilder setPassword(String password) {
return setProperty(PersistenceUnitProperties.JDBC_PASSWORD, password);
}
/**
* Sets the value of {@value PersistenceUnitProperties#EXCEPTION_HANDLER_CLASS} property.
*/
public PersistTestModuleBuilder setExceptionHandler(Class<? extends ExceptionHandler> exHandler) {
return setProperty(PersistenceUnitProperties.EXCEPTION_HANDLER_CLASS, exHandler.getName());
}
/**
* Adds class to the listing of the entities defined by persistence unit.
*/
public PersistTestModuleBuilder addEntityClass(Class<?> entityClass) {
entityFqnSet.add(entityClass.getName());
return this;
}
/**
* Adds class to the listing of the entities defined by persistence unit.
*/
public PersistTestModuleBuilder addEntityClass(String fqn) {
entityFqnSet.add(fqn);
return this;
}
/**
* Batch add of entity classes to the persistence unit listing.
*/
public PersistTestModuleBuilder addEntityClasses(Class<?>... entityClasses) {
for (Class<?> entityClass : entityClasses) {
addEntityClass(entityClass);
}
return this;
}
/**
* Sets persistence unit custom property.
*/
public PersistTestModuleBuilder setProperty(String name, String value) {
if (name != null && value != null) {
properties.put(name, value);
}
return this;
}
/**
* Sets the the value of {@link PersistenceUnitProperties#LOGGING_LEVEL} property.
*/
public PersistTestModuleBuilder setLogLevel(String logLevel) {
return setProperty(PersistenceUnitProperties.LOGGING_LEVEL, logLevel);
}
/**
* Sets the name of persistence unit.
*/
public PersistTestModuleBuilder setPersistenceUnit(String persistenceUnit) {
this.persistenceUnit = persistenceUnit;
return this;
}
/**
* Creates or overrides META-INF/persistence.xml.
*/
public Path savePersistenceXml() throws IOException, URISyntaxException {
Path persistenceXmlPath = getOrCreateMetaInf().resolve("persistence.xml");
URL url = Thread.currentThread().getContextClassLoader().getResource(PERSISTENCE_XML_TEMPLATE_RESOURCE_PATH);
if (url == null) {
throw new IOException("Resource '" + PERSISTENCE_XML_TEMPLATE_RESOURCE_PATH + "' doesn't exist");
}
ST st = new ST(Resources.toString(url, UTF_8), '$', '$');
if (persistenceUnit != null) {
st.add("unit", persistenceUnit);
}
if (!entityFqnSet.isEmpty()) {
st.add("entity_classes", entityFqnSet);
}
if (!properties.isEmpty()) {
st.add("properties", properties);
}
Files.write(persistenceXmlPath, st.render().getBytes(UTF_8));
return persistenceXmlPath;
}
/**
* Creates persistence.xml and builds module for testing.
*/
public Module build() {
return new PersistTestModule();
}
private class PersistTestModule extends AbstractModule {
@Override
protected void configure() {
try {
savePersistenceXml();
} catch (Exception x) {
throw new RuntimeException(x.getMessage());
}
install(new JpaPersistModule(persistenceUnit));
}
}
private Path getOrCreateMetaInf() throws URISyntaxException, IOException {
Path root = Paths.get(Thread.currentThread().getContextClassLoader().getResource(".").toURI());
Path metaInf = root.resolve("META-INF");
if (!Files.exists(metaInf)) {
Files.createDirectory(metaInf);
}
return metaInf;
}
}