/* | |
* 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.jpa.container.impl; | |
import static java.util.Collections.singletonMap; | |
import static javax.persistence.spi.PersistenceUnitTransactionType.JTA; | |
import static javax.persistence.spi.PersistenceUnitTransactionType.RESOURCE_LOCAL; | |
import static org.junit.Assert.assertEquals; | |
import static org.junit.Assert.assertSame; | |
import static org.junit.Assert.fail; | |
import static org.mockito.AdditionalMatchers.and; | |
import static org.mockito.AdditionalMatchers.not; | |
import static org.mockito.Matchers.any; | |
import static org.mockito.Matchers.anyMap; | |
import static org.mockito.Matchers.argThat; | |
import static org.mockito.Matchers.eq; | |
import static org.mockito.Mockito.verify; | |
import static org.mockito.Mockito.verifyZeroInteractions; | |
import static org.mockito.Mockito.when; | |
import static org.osgi.framework.Constants.SERVICE_PID; | |
import static org.osgi.service.jpa.EntityManagerFactoryBuilder.JPA_UNIT_NAME; | |
import java.util.Dictionary; | |
import java.util.HashMap; | |
import java.util.Hashtable; | |
import java.util.Map; | |
import java.util.Properties; | |
import javax.persistence.EntityManagerFactory; | |
import javax.persistence.spi.PersistenceProvider; | |
import javax.persistence.spi.PersistenceUnitInfo; | |
import javax.persistence.spi.PersistenceUnitTransactionType; | |
import javax.sql.DataSource; | |
import org.apache.aries.jpa.container.parser.impl.PersistenceUnit; | |
import org.hamcrest.BaseMatcher; | |
import org.hamcrest.Description; | |
import org.junit.Before; | |
import org.junit.Test; | |
import org.junit.runner.RunWith; | |
import org.mockito.ArgumentCaptor; | |
import org.mockito.Mock; | |
import org.mockito.Mockito; | |
import org.mockito.invocation.InvocationOnMock; | |
import org.mockito.runners.MockitoJUnitRunner; | |
import org.mockito.stubbing.Answer; | |
import org.osgi.framework.Bundle; | |
import org.osgi.framework.BundleContext; | |
import org.osgi.framework.Filter; | |
import org.osgi.framework.FrameworkUtil; | |
import org.osgi.framework.InvalidSyntaxException; | |
import org.osgi.framework.ServiceReference; | |
import org.osgi.framework.ServiceRegistration; | |
import org.osgi.framework.Version; | |
import org.osgi.service.cm.ConfigurationException; | |
import org.osgi.service.cm.ManagedService; | |
import org.osgi.service.jdbc.DataSourceFactory; | |
@RunWith(MockitoJUnitRunner.class) | |
public class PropsConfigurationTest { | |
private static final String ECLIPSE_PERSISTENCE_PROVIDER = "org.eclipse.persistence.jpa.PersistenceProvider"; | |
private static final String JDBC_PASSWORD = "123456"; | |
private static final String JDBC_USER = "bob"; | |
private static final String JDBC_URL = "jdbc:h2:foo"; | |
@Mock | |
PersistenceUnit punit; | |
@Mock | |
ServiceRegistration<ManagedService> msReg; | |
@Mock | |
PersistenceProvider provider; | |
@Mock | |
BundleContext containerContext, punitContext; | |
@Mock | |
Bundle punitBundle, providerBundle; | |
@Mock | |
EntityManagerFactory emf; | |
@Mock | |
ServiceRegistration<EntityManagerFactory> emfReg; | |
Properties punitProperties = new Properties(); | |
@Mock | |
ServiceReference<DataSourceFactory> dsfRef; | |
@Mock | |
ServiceReference<DataSource> dsRef; | |
@Mock | |
DataSourceFactory dsf; | |
@Mock | |
DataSource ds; | |
@SuppressWarnings("unchecked") | |
@Before | |
public void setup() throws Exception { | |
when(punit.getPersistenceUnitName()).thenReturn("test-props"); | |
when(punit.getPersistenceProviderClassName()) | |
.thenReturn(ECLIPSE_PERSISTENCE_PROVIDER); | |
when(punit.getTransactionType()).thenReturn(PersistenceUnitTransactionType.JTA); | |
when(punit.getBundle()).thenReturn(punitBundle); | |
when(punit.getProperties()).thenReturn(punitProperties); | |
when(punitBundle.getBundleContext()).thenReturn(punitContext); | |
when(punitBundle.getVersion()).thenReturn(Version.parseVersion("1.2.3")); | |
when(containerContext.registerService(eq(ManagedService.class), | |
any(ManagedService.class), any(Dictionary.class))).thenReturn(msReg); | |
when(containerContext.getService(dsfRef)).thenReturn(dsf); | |
when(containerContext.getService(dsRef)).thenReturn(ds); | |
when(containerContext.createFilter(Mockito.anyString())) | |
.thenAnswer(new Answer<Filter>() { | |
@Override | |
public Filter answer(InvocationOnMock i) throws Throwable { | |
return FrameworkUtil.createFilter(i.getArguments()[0].toString()); | |
} | |
}); | |
when(punitContext.registerService(eq(EntityManagerFactory.class), any(EntityManagerFactory.class), | |
any(Dictionary.class))).thenReturn(emfReg); | |
when(emf.isOpen()).thenReturn(true); | |
Properties jdbcProps = new Properties(); | |
jdbcProps.setProperty("url", JDBC_URL); | |
jdbcProps.setProperty("user", JDBC_USER); | |
jdbcProps.setProperty("password", JDBC_PASSWORD); | |
when(dsf.createDataSource(jdbcProps)).thenReturn(ds); | |
} | |
@Test | |
public void testRegistersManagedEMF() throws InvalidSyntaxException, ConfigurationException { | |
AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder( | |
containerContext, provider, providerBundle, punit); | |
verify(containerContext).registerService(eq(ManagedService.class), | |
any(ManagedService.class), argThat(servicePropsMatcher( | |
SERVICE_PID, "org.apache.aries.jpa.test-props"))); | |
// No EMF created as incomplete | |
verifyZeroInteractions(msReg, provider); | |
emfb.close(); | |
verify(msReg).unregister(); | |
} | |
private BaseMatcher<Dictionary<String, Object>> servicePropsMatcher(final String key, final Object value) { | |
return new BaseMatcher<Dictionary<String, Object>>() { | |
Object props; | |
@SuppressWarnings("unchecked") | |
@Override | |
public boolean matches(Object arg0) { | |
props = arg0; | |
return value.equals(((Dictionary<String, Object>) props).get(key)); | |
} | |
@Override | |
public void describeTo(Description arg0) { | |
arg0.appendText("Service Properties did not contain " + key + | |
"=" + value + ". Props were " + props); | |
} | |
}; | |
} | |
@Test | |
public void testIncompleteEmfWithoutProps() throws InvalidSyntaxException, ConfigurationException { | |
when(provider.createContainerEntityManagerFactory(eq(punit), | |
eq(singletonMap(PersistenceUnitTransactionType.class.getName(), JTA)))) | |
.thenReturn(emf); | |
AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder( | |
containerContext, provider, providerBundle, punit); | |
assertEquals(ECLIPSE_PERSISTENCE_PROVIDER, emfb.getPersistenceProviderName()); | |
assertEquals(providerBundle, emfb.getPersistenceProviderBundle()); | |
try { | |
emfb.createEntityManagerFactory(null); | |
fail("Should throw an exception as incomplete"); | |
} catch (IllegalArgumentException iae) { | |
// Expected | |
} | |
// No EMF created as incomplete | |
verifyZeroInteractions(emf, emfReg, provider); | |
emfb.close(); | |
verifyZeroInteractions(emf, emfReg, provider); | |
} | |
@Test | |
public void testIncompleteEmfWithDSGetsPassed() throws InvalidSyntaxException, ConfigurationException { | |
when(provider.createContainerEntityManagerFactory(eq(punit), | |
eq(singletonMap(PersistenceUnitTransactionType.class.getName(), JTA)))) | |
.thenReturn(emf); | |
Map<String, Object> props = new Hashtable<String, Object>(); | |
props.put("javax.persistence.dataSource", ds); | |
AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder( | |
containerContext, provider, providerBundle, punit); | |
assertEquals(ECLIPSE_PERSISTENCE_PROVIDER, emfb.getPersistenceProviderName()); | |
assertEquals(providerBundle, emfb.getPersistenceProviderBundle()); | |
emfb.createEntityManagerFactory(props); | |
verify(punit).setNonJtaDataSource(ds); | |
verify(punitContext).registerService(eq(EntityManagerFactory.class), | |
any(EntityManagerFactory.class), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props"))); | |
emfb.close(); | |
verify(emfReg).unregister(); | |
verify(emf).close(); | |
} | |
@Test | |
public void testIncompleteEmfWithPropsGetsPassed() throws InvalidSyntaxException, ConfigurationException { | |
Map<String, Object> providerProps = new HashMap<String, Object>(); | |
providerProps.put(PersistenceUnitTransactionType.class.getName(), JTA); | |
providerProps.put("hibernate.hbm2ddl.auto", "create-drop"); | |
when(provider.createContainerEntityManagerFactory(eq(punit), | |
eq(providerProps))).thenReturn(emf); | |
Map<String, Object> props = new Hashtable<String, Object>(); | |
props.put("hibernate.hbm2ddl.auto", "create-drop"); | |
props.put("javax.persistence.dataSource", ds); | |
AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder( | |
containerContext, provider, providerBundle, punit); | |
emfb.createEntityManagerFactory(props); | |
verify(punitContext).registerService(eq(EntityManagerFactory.class), | |
any(EntityManagerFactory.class), and(argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")), | |
argThat(servicePropsMatcher("hibernate.hbm2ddl.auto", "create-drop")))); | |
emfb.close(); | |
verify(emfReg).unregister(); | |
verify(emf).close(); | |
} | |
@Test | |
public void testPUWithDriverGetsCreatedAutomatically() throws InvalidSyntaxException, ConfigurationException { | |
punitProperties.setProperty("javax.persistence.jdbc.driver", "org.h2.Driver"); | |
punitProperties.setProperty("javax.persistence.jdbc.url", JDBC_URL); | |
punitProperties.setProperty("javax.persistence.jdbc.user", JDBC_USER); | |
punitProperties.setProperty("javax.persistence.jdbc.password", JDBC_PASSWORD); | |
when(containerContext.getServiceReferences((String) null, | |
"(&(objectClass=org.osgi.service.jdbc.DataSourceFactory)(osgi.jdbc.driver.class=org.h2.Driver))")) | |
.thenReturn(new ServiceReference<?>[] {dsfRef}); | |
when(provider.createContainerEntityManagerFactory(eq(punit), | |
any(Map.class))).thenReturn(emf); | |
AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder( | |
containerContext, provider, providerBundle, punit); | |
verify(punit).setJtaDataSource(ds); | |
verify(punitContext).registerService(eq(EntityManagerFactory.class), | |
any(EntityManagerFactory.class), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props"))); | |
emfb.close(); | |
verify(emfReg).unregister(); | |
verify(emf).close(); | |
} | |
@Test | |
public void testPUWithDriverEMFBReturnsExisting() throws InvalidSyntaxException, ConfigurationException { | |
punitProperties.setProperty("javax.persistence.jdbc.driver", "org.h2.Driver"); | |
punitProperties.setProperty("javax.persistence.jdbc.url", JDBC_URL); | |
punitProperties.setProperty("javax.persistence.jdbc.user", JDBC_USER); | |
punitProperties.setProperty("javax.persistence.jdbc.password", JDBC_PASSWORD); | |
when(containerContext.getServiceReferences((String) null, | |
"(&(objectClass=org.osgi.service.jdbc.DataSourceFactory)(osgi.jdbc.driver.class=org.h2.Driver))")) | |
.thenReturn(new ServiceReference<?>[] {dsfRef}); | |
when(provider.createContainerEntityManagerFactory(eq(punit), | |
any(Map.class))).thenReturn(emf); | |
AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder( | |
containerContext, provider, providerBundle, punit); | |
verify(punit).setJtaDataSource(ds); | |
verify(punitContext).registerService(eq(EntityManagerFactory.class), | |
any(EntityManagerFactory.class), | |
and(and(argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props")), | |
argThat(servicePropsMatcher("javax.persistence.jdbc.user", JDBC_USER))), | |
not(argThat(servicePropsMatcher("javax.persistence.jdbc.password", JDBC_PASSWORD))))); | |
assertSame(emf, emfb.createEntityManagerFactory(null)); | |
assertSame(emf, emfb.createEntityManagerFactory(new HashMap<String, Object>())); | |
verify(provider, Mockito.times(1)).createContainerEntityManagerFactory( | |
any(PersistenceUnitInfo.class), anyMap()); | |
emfb.close(); | |
verify(emfReg).unregister(); | |
verify(emf).close(); | |
} | |
@Test | |
public void testLateBindingDriver() throws InvalidSyntaxException, ConfigurationException { | |
when(containerContext.getServiceReferences((String) null, | |
"(&(objectClass=org.osgi.service.jdbc.DataSourceFactory)(osgi.jdbc.driver.class=org.h2.Driver))")) | |
.thenReturn(new ServiceReference<?>[] {dsfRef}); | |
when(provider.createContainerEntityManagerFactory(eq(punit), | |
any(Map.class))).thenReturn(emf); | |
AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder( | |
containerContext, provider, providerBundle, punit); | |
verifyZeroInteractions(provider); | |
Map<String, Object> config = new HashMap<String, Object>(); | |
config.put("javax.persistence.jdbc.driver", "org.h2.Driver"); | |
config.put("javax.persistence.jdbc.url", JDBC_URL); | |
config.put("javax.persistence.jdbc.user", JDBC_USER); | |
config.put("javax.persistence.jdbc.password", JDBC_PASSWORD); | |
emfb.createEntityManagerFactory(config); | |
verify(punit).setJtaDataSource(ds); | |
verify(punitContext).registerService(eq(EntityManagerFactory.class), | |
any(EntityManagerFactory.class), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props"))); | |
try { | |
config.put("javax.persistence.jdbc.driver", "org.apache.derby.client.ClientDriver"); | |
emfb.createEntityManagerFactory(config); | |
fail("Must throw an IllegalArgumentException on rebind"); | |
} catch (IllegalArgumentException ise) { | |
// Expected | |
} | |
emfb.close(); | |
} | |
@Test | |
public void testPUWithJtaDSGetsCreatedAutomatically() throws InvalidSyntaxException, ConfigurationException { | |
when(containerContext.getServiceReferences((String) null, | |
"(&(objectClass=javax.sql.DataSource)(osgi.jndi.service.name=testds))")) | |
.thenReturn(new ServiceReference<?>[] {dsRef}); | |
when(punit.getJtaDataSourceName()).thenReturn( | |
"osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=testds)"); | |
when(provider.createContainerEntityManagerFactory(eq(punit), | |
any(Map.class))).thenReturn(emf); | |
AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder( | |
containerContext, provider, providerBundle, punit); | |
verify(punit).setJtaDataSource(ds); | |
verify(punitContext).registerService(eq(EntityManagerFactory.class), | |
any(EntityManagerFactory.class), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props"))); | |
emfb.close(); | |
} | |
@Test | |
public void testPUWithNonJtaDSGetsCreatedAutomatically() throws InvalidSyntaxException, ConfigurationException { | |
when(containerContext.getServiceReferences((String) null, | |
"(&(objectClass=javax.sql.DataSource)(osgi.jndi.service.name=testds))")) | |
.thenReturn(new ServiceReference<?>[] {dsRef}); | |
when(punit.getTransactionType()).thenReturn(RESOURCE_LOCAL); | |
when(punit.getNonJtaDataSourceName()).thenReturn( | |
"osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=testds)"); | |
when(provider.createContainerEntityManagerFactory(eq(punit), | |
any(Map.class))).thenReturn(emf); | |
AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder( | |
containerContext, provider, providerBundle, punit); | |
verify(punit).setNonJtaDataSource(ds); | |
verify(punitContext).registerService(eq(EntityManagerFactory.class), | |
any(EntityManagerFactory.class), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props"))); | |
emfb.close(); | |
} | |
@Test | |
public void testReturnedEmfClose() throws InvalidSyntaxException, ConfigurationException { | |
when(provider.createContainerEntityManagerFactory(eq(punit), | |
eq(singletonMap(PersistenceUnitTransactionType.class.getName(), JTA)))) | |
.thenReturn(emf); | |
Map<String, Object> props = new Hashtable<String, Object>(); | |
props.put("javax.persistence.dataSource", ds); | |
AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder( | |
containerContext, provider, providerBundle, punit); | |
EntityManagerFactory returnedEMF = emfb.createEntityManagerFactory(props); | |
verify(punit).setNonJtaDataSource(ds); | |
verify(punitContext).registerService(eq(EntityManagerFactory.class), | |
any(EntityManagerFactory.class), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props"))); | |
returnedEMF.close(); | |
verify(emfReg).unregister(); | |
verify(emf).close(); | |
emfb.close(); | |
} | |
@Test | |
public void testServiceEmfClose() throws InvalidSyntaxException, ConfigurationException { | |
when(provider.createContainerEntityManagerFactory(eq(punit), | |
eq(singletonMap(PersistenceUnitTransactionType.class.getName(), JTA)))) | |
.thenReturn(emf); | |
Map<String, Object> props = new Hashtable<String, Object>(); | |
props.put("javax.persistence.dataSource", ds); | |
AriesEntityManagerFactoryBuilder emfb = new AriesEntityManagerFactoryBuilder( | |
containerContext, provider, providerBundle, punit); | |
emfb.createEntityManagerFactory(props); | |
ArgumentCaptor<EntityManagerFactory> emfCaptor = ArgumentCaptor.forClass(EntityManagerFactory.class); | |
verify(punit).setNonJtaDataSource(ds); | |
verify(punitContext).registerService(eq(EntityManagerFactory.class), | |
emfCaptor.capture(), argThat(servicePropsMatcher(JPA_UNIT_NAME, "test-props"))); | |
emfCaptor.getValue().close(); | |
verifyZeroInteractions(emfReg, emf); | |
emfb.close(); | |
} | |
} |