blob: 4f6673a14180c08100c9cec31accbfcec8615d29 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 WARRANTIESOR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.aries.tx.control.jpa.local.impl;
import static java.util.Optional.ofNullable;
import static javax.persistence.spi.PersistenceUnitTransactionType.RESOURCE_LOCAL;
import static org.osgi.service.transaction.control.jpa.JPAEntityManagerProviderFactory.LOCAL_ENLISTMENT_ENABLED;
import static org.osgi.service.transaction.control.jpa.JPAEntityManagerProviderFactory.XA_ENLISTMENT_ENABLED;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.sql.DataSource;
import org.apache.aries.tx.control.jpa.common.impl.AbstractJPAEntityManagerProvider;
import org.apache.aries.tx.control.jpa.common.impl.InternalJPAEntityManagerProviderFactory;
import org.apache.aries.tx.control.jpa.common.impl.JPADataSourceHelper;
import org.osgi.service.jpa.EntityManagerFactoryBuilder;
import org.osgi.service.transaction.control.TransactionException;
import com.zaxxer.hikari.HikariDataSource;
public class JPAEntityManagerProviderFactoryImpl implements InternalJPAEntityManagerProviderFactory {
@Override
public AbstractJPAEntityManagerProvider getProviderFor(EntityManagerFactoryBuilder emfb, Map<String, Object> jpaProperties,
Map<String, Object> resourceProviderProperties) {
checkEnlistment(resourceProviderProperties);
Object found = jpaProperties.get("javax.persistence.dataSource");
if(found == null) {
found = jpaProperties.get("javax.persistence.nonJtaDataSource");
}
if(found == null) {
throw new IllegalArgumentException("No datasource was found when checking the javax.persistence.dataSource and javax.persistence.nonJtaDataSource.");
}
DataSource unpooled;
if(found instanceof DataSource) {
unpooled = (DataSource) found;
} else {
throw new IllegalArgumentException("The object found when checking the javax.persistence.dataSource and javax.persistence.nonJtaDataSource properties was not a DataSource.");
}
Map<String, Object> jpaPropsToUse = new HashMap<>(jpaProperties);
DataSource toUse = JPADataSourceHelper.poolIfNecessary(resourceProviderProperties, unpooled);
jpaPropsToUse.put("javax.persistence.dataSource", toUse);
jpaPropsToUse.put("javax.persistence.nonJtaDataSource", toUse);
EntityManagerFactory emf = emfb.createEntityManagerFactory(jpaPropsToUse);
validateEMF(emf);
return new JPAEntityManagerProviderImpl(emf, () -> {
emf.close();
if (toUse instanceof HikariDataSource) {
((HikariDataSource)toUse).close();
}
});
}
public AbstractJPAEntityManagerProvider getProviderFor(EntityManagerFactoryBuilder emfb,
Map<String, Object> jpaProperties, Map<String, Object> resourceProviderProperties,
Runnable onClose) {
checkEnlistment(resourceProviderProperties);
EntityManagerFactory emf = emfb.createEntityManagerFactory(jpaProperties);
validateEMF(emf);
return new JPAEntityManagerProviderImpl(emf, () -> {
try {
emf.close();
} catch (Exception e) {
}
if (onClose != null) {
onClose.run();
}
});
}
private void validateEMF(EntityManagerFactory emf) {
Object o = emf.getProperties().get("javax.persistence.transactionType");
PersistenceUnitTransactionType tranType;
if(o instanceof PersistenceUnitTransactionType) {
tranType = (PersistenceUnitTransactionType) o;
} else if (o instanceof String) {
tranType = PersistenceUnitTransactionType.valueOf(o.toString());
} else {
//TODO log this?
tranType = RESOURCE_LOCAL;
}
if(RESOURCE_LOCAL != tranType) {
throw new IllegalArgumentException("The supplied EntityManagerFactory is not declared RESOURCE_LOCAL");
}
}
@Override
public AbstractJPAEntityManagerProvider getProviderFor(EntityManagerFactory emf,
Map<String, Object> resourceProviderProperties) {
checkEnlistment(resourceProviderProperties);
validateEMF(emf);
return new JPAEntityManagerProviderImpl(emf, null);
}
private void checkEnlistment(Map<String, Object> resourceProviderProperties) {
if (toBoolean(resourceProviderProperties, XA_ENLISTMENT_ENABLED, false)) {
throw new TransactionException("This Resource Provider does not support XA transactions");
} else if (!toBoolean(resourceProviderProperties, LOCAL_ENLISTMENT_ENABLED, true)) {
throw new TransactionException(
"This Resource Provider always enlists in local transactions as it does not support XA");
}
}
private boolean toBoolean(Map<String, Object> props, String key, boolean defaultValue) {
Object o = ofNullable(props)
.map(m -> m.get(key))
.orElse(defaultValue);
if (o instanceof Boolean) {
return ((Boolean) o).booleanValue();
} else if(o instanceof String) {
return Boolean.parseBoolean((String) o);
} else {
throw new IllegalArgumentException("The property " + key + " cannot be converted to a boolean");
}
}
}