org.eiichiro.gig.heroku.HerokuPostgresJPAEntityManagerFactoryComponent Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gig-jpa-heroku-postgres Show documentation
Show all versions of gig-jpa-heroku-postgres Show documentation
JPA components for Heroku Postgres with EclipseLink
/*
* Copyright (C) 2012 Eiichiro Uchiumi. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eiichiro.gig.heroku;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceException;
import org.eiichiro.jaguar.Component;
import org.eiichiro.jaguar.inject.Name;
import org.eiichiro.jaguar.lifecycle.Constructed;
import org.eiichiro.jaguar.lifecycle.Passivated;
import org.eiichiro.jaguar.scope.Singleton;
import org.eiichiro.reverb.system.Environment;
import org.postgresql.Driver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@code HerokuPostgresJPAEntityManagerFactoryComponent} is a representing JPA 2.0
* {@code EntityManagerFactory} for PostgreSQL-based Heroku database service.
*
* @author Eiichiro Uchiumi
*/
@Name("org.eiichiro.gig.heroku.HerokuPostgresJPAEntityManagerFactory")
@Singleton
@Heroku
public class HerokuPostgresJPAEntityManagerFactoryComponent extends Component {
private static final String DATABASE_URL = "DATABASE_URL";
private static final String JDBC_DRIVER = "javax.persistence.jdbc.driver";
private static final String JDBC_URL = "javax.persistence.jdbc.url";
private static final String JDBC_USER = "javax.persistence.jdbc.user";
private static final String JDBC_PASSWORD = "javax.persistence.jdbc.password";
private Logger logger = LoggerFactory.getLogger(getClass());
private Map properties = new HashMap();
private List persistenceUnits = new ArrayList();
private Map factories = new ConcurrentHashMap();
/**
* Configures JPA's JDBC connection properties from the environment variable
* 'DATABASE_URL' and gets the persistence units to be connected from a
* {@code PersistenceXMLProcessor}.
*/
@Constructed
public void configure() {
String database = Environment.getenv(DATABASE_URL);
if (database == null) {
logger.warn("Environment variable [$" + DATABASE_URL + "] has not been specified; " +
"So you don't have access to the database service in this application");
} else {
logger.info("$DATABASE_URL is [" + database + "]");
try {
URI uri = new URI(database);
Map properties = new HashMap();
properties.put(JDBC_DRIVER, Driver.class.getName());
properties.put(JDBC_URL, "jdbc:postgresql://" + uri.getHost() + uri.getPath());
properties.put(JDBC_USER, uri.getUserInfo().split(":")[0]);
properties.put(JDBC_PASSWORD, uri.getUserInfo().split(":")[1]);
PersistenceXMLProcessor processor = new PersistenceXMLProcessor();
processor.process();
persistenceUnits = processor.persistenceUnits();
this.properties = properties;
} catch (Exception e) {
logger.error("Failed to configure JPA's JDBC connection properties: " +
"$DATABASE_URL is [" + database + "]", e);
}
}
}
/** Lifecycle callback to close the {@code EntityManagerFactory} set. */
@Passivated
public void close() {
for (EntityManagerFactory factory : factories.values()) {
factory.close();
}
persistenceUnits.clear();
properties.clear();
}
/**
* Returns the {@code EntityManagerFactory} instance corresponding to the
* persistence unit the current application connects.
* If the {@code PersistenceXMLProcessor} detects multiple persistence unit
* declarations, this class connects the first-detected one (Index 0 of the
* persistence unit list that the {@code PersistenceXMLProcessor#persistenceUnits()}
* returns).
* If the current application cannot access to the database service for any
* reasons, this method returns null
.
*
* Note: In the future, the implementation will be improved for
* multitenant applications. The persistence unit set on the current thread
* via something like "Namespaces API" will be used for the
* {@code EntityManagerFactory} creation.
*
* @return The {@code EntityManagerFactory} instance corresponding to the
* persistence unit the current application connects.
*/
@Override
public EntityManagerFactory instance() {
if (!persistenceUnits.isEmpty()) {
EntityManagerFactory factory = factories.get(persistenceUnits.get(0));
if (factory == null) {
try {
factory = Persistence.createEntityManagerFactory(persistenceUnits.get(0), properties);
factories.put(persistenceUnits.get(0), factory);
logger.info("EntityManagerFactory for persistence unit ["
+ persistenceUnits.get(0) + "] created");
} catch (PersistenceException e) {
logger.error("Failed to create EntityManagerFactory", e);
}
}
return factory;
}
logger.warn("Cannot access to the database service in this application; " +
"Returned 'EntityManagerFactory' instance is null");
return null;
}
public Map properties() {
return properties;
}
public List persistenceUnits() {
return persistenceUnits;
}
}