killbill-aplcache
Changes
.gitignore 3(+2 -1)
beatrix/pom.xml 23(+23 -0)
beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestBasicOSGIWithTestBundle.java 252(+252 -0)
osgi-bundles/pom.xml 1(+1 -0)
osgi-bundles/test/pom.xml 154(+154 -0)
osgi-bundles/test/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java 112(+112 -0)
pom.xml 8(+8 -0)
Details
.gitignore 3(+2 -1)
diff --git a/.gitignore b/.gitignore
index 6fa2692..ba3098e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,4 +16,5 @@ logs/
*.project
*/bin/
catalog/src/test/resources/CatalogSchema.xsd
-*/test-output/
\ No newline at end of file
+*/test-output/
+beatrix/src/test/resources/killbill-osgi-bundles-test-*-jar-with-dependencies.jar
beatrix/pom.xml 23(+23 -0)
diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index 5ccf002..fb512bd 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -57,6 +57,10 @@
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
+ <artifactId>killbill-osgi-bundles-test</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
<artifactId>killbill-tenant</artifactId>
</dependency>
<dependency>
@@ -183,6 +187,25 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>1.4</version>
+ <executions>
+ <execution>
+ <id>copy</id>
+ <phase>initialize</phase>
+ <configuration>
+ <tasks>
+ <copy file="${basedir}/../osgi-bundles/test/target/killbill-osgi-bundles-test-${project.version}-jar-with-dependencies.jar" tofile="${basedir}/src/test/resources/killbill-osgi-bundles-test-${project.version}-jar-with-dependencies.jar"/>
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
</plugins>
</build>
</project>
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java
index 35acacf..7399ddf 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixIntegrationModule.java
@@ -18,6 +18,7 @@ package com.ning.billing.beatrix.integration;
import java.io.IOException;
import java.net.URL;
+import java.util.Properties;
import java.util.Set;
import com.ning.billing.GuicyKillbillTestWithEmbeddedDBModule;
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestBasicOSGIWithTestBundle.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestBasicOSGIWithTestBundle.java
new file mode 100644
index 0000000..df39b19
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestBasicOSGIWithTestBundle.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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
+ * 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 com.ning.billing.beatrix.integration.osgi;
+
+import java.math.BigDecimal;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+
+import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.Query;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.TransactionCallback;
+import org.skife.jdbi.v2.TransactionStatus;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.beatrix.osgi.SetupBundleWithAssertion;
+import com.ning.billing.dbi.DBTestingHelper;
+import com.ning.billing.osgi.api.OSGIServiceRegistration;
+import com.ning.billing.osgi.glue.OSGIDataSourceConfig;
+import com.ning.billing.payment.plugin.api.PaymentInfoPlugin;
+import com.ning.billing.payment.plugin.api.PaymentPluginApi;
+
+import static com.jayway.awaitility.Awaitility.await;
+
+/**
+ * Basic OSGI test that relies on the 'test' bundle (com.ning.billing.osgi.bundles.test.TestActivator)
+ * <p/>
+ * The test checks that the bundle:
+ * - gets started
+ * - can make API call
+ * - can listen to KB events
+ * - can register a service (PaymentPluginApi) that this test calls
+ * - can write in the DB using the DataSource (this is how the assertion work)
+ */
+public class TestBasicOSGIWithTestBundle extends TestOSGIBase {
+
+ private final String BUNDLE_TEST_RESOURCE = "killbill-osgi-bundles-test";
+
+ @Inject
+ private OSGIServiceRegistration<PaymentPluginApi> paymentPluginApiOSGIServiceRegistration;
+
+ @BeforeClass(groups = "slow")
+ public void setup() throws Exception {
+
+ final String jdbcConnection = getDBTestingHelper().getJdbcConnectionString();
+ final String userName = DBTestingHelper.USERNAME;
+ final String userPwd = DBTestingHelper.PASSWORD;
+
+ System.setProperty(OSGIDataSourceConfig.DATA_SOURCE_PROP_PREFIX + "jdbc.url", jdbcConnection);
+ System.setProperty(OSGIDataSourceConfig.DATA_SOURCE_PROP_PREFIX + "jdbc.user", userName);
+ System.setProperty(OSGIDataSourceConfig.DATA_SOURCE_PROP_PREFIX + "jdbc.password", userPwd);
+
+ // OSGIDataSourceConfig
+ super.setup();
+
+ // This is extracted from surefire system configuration-- needs to be added explicitely in IntelliJ for correct running
+ final String killbillVersion = System.getProperty("killbill.version");
+ SetupBundleWithAssertion setupTest = new SetupBundleWithAssertion(BUNDLE_TEST_RESOURCE, osgiConfig, killbillVersion);
+ setupTest.setupBundle();
+
+ }
+
+ @Test(groups = "slow")
+ public void testBundleTest() throws Exception {
+
+ // At this point test bundle should have been started already
+ final TestActivatorWithAssertion assertTor = new TestActivatorWithAssertion(getDBI());
+ assertTor.assertPluginInitialized();
+
+ // Create an account and expect test bundle listen to KB events and write the external name in its table
+ final Account account = createAccountWithPaymentMethod(getAccountData(1));
+ assertTor.assertPluginReceievdAccountCreationEvent(account.getExternalKey());
+
+ // Retrieve the PaymentPluginApi that the test bundle registered
+ final PaymentPluginApi paymentPluginApi = getTestPluginPaymentApi();
+
+ // Make a payment and expect test bundle to correcly write in its table the input values
+ final UUID paymentId = UUID.randomUUID();
+ final BigDecimal paymentAmount = new BigDecimal("14.32");
+ final PaymentInfoPlugin r = paymentPluginApi.processPayment(paymentId, account.getPaymentMethodId(), paymentAmount, callContext);
+ assertTor.assertPluginCreatedPayment(paymentId, account.getPaymentMethodId(), paymentAmount);
+ }
+
+ private PaymentPluginApi getTestPluginPaymentApi() {
+ PaymentPluginApi result = paymentPluginApiOSGIServiceRegistration.getServiceForPluginName("test");
+ Assert.assertNotNull(result);
+ return result;
+ }
+
+ private static final class TestActivatorWithAssertion {
+
+ private final IDBI dbi;
+
+ public TestActivatorWithAssertion(final IDBI dbi) {
+ this.dbi = dbi;
+ }
+
+ public void assertPluginInitialized() {
+ assertWithCallback(new AwaitCallback() {
+ @Override
+ public boolean isSuccess() {
+ return isPluginInitialized();
+ }
+ }, "Plugin did not complete initialization");
+ }
+
+ public void assertPluginReceievdAccountCreationEvent(final String expectedExternalKey) {
+ assertWithCallback(new AwaitCallback() {
+ @Override
+ public boolean isSuccess() {
+ return isValidAccountExternalKey(expectedExternalKey);
+ }
+ }, "Plugin did not receive account creation event");
+ }
+
+ public void assertPluginCreatedPayment(final UUID expectedPaymentId, final UUID expectedPaymentMethodId, final BigDecimal expectedAmount) {
+ assertWithCallback(new AwaitCallback() {
+ @Override
+ public boolean isSuccess() {
+ return isValidPayment(expectedPaymentId, expectedPaymentMethodId, expectedAmount);
+ }
+ }, "Plugin did not create the payment");
+ }
+
+
+ private void assertWithCallback(final AwaitCallback callback, final String error) {
+ try {
+ await().atMost(5, TimeUnit.SECONDS).until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return callback.isSuccess();
+ }
+ });
+ } catch (Exception e) {
+ Assert.fail(error, e);
+ }
+ }
+
+ private boolean isValidPayment(final UUID expectedPaymentId, final UUID expectedPaymentMethodId, final BigDecimal expectedAmount) {
+ TestModel test = getTestModelFirstRecord();
+ return expectedPaymentId.equals(test.getPaymentId()) &&
+ expectedPaymentMethodId.equals(test.getPaymentMethodId()) &&
+ expectedAmount.compareTo(test.getAmount()) == 0;
+ }
+
+
+ private boolean isPluginInitialized() {
+ TestModel test = getTestModelFirstRecord();
+ return test.isStarted();
+ }
+
+ private boolean isValidAccountExternalKey(final String expectedExternalKey) {
+ TestModel test = getTestModelFirstRecord();
+ return expectedExternalKey.equals(test.getAccountExternalKey());
+ }
+
+ private TestModel getTestModelFirstRecord() {
+ TestModel test = dbi.inTransaction(new TransactionCallback<TestModel>() {
+ @Override
+ public TestModel inTransaction(final Handle conn, final TransactionStatus status) throws Exception {
+ Query<Map<String, Object>> q = conn.createQuery("SELECT is_started, external_key, payment_id, payment_method_id, payment_amount FROM test_bundle WHERE record_id = 1;");
+ TestModel test = q.map(new TestMapper()).first();
+ return test;
+ }
+ });
+ return test;
+ }
+ }
+
+
+ private final static class TestModel {
+
+ private final Boolean isStarted;
+ private final String accountExternalKey;
+ private final UUID paymentId;
+ private final UUID paymentMethodId;
+ private final BigDecimal amount;
+
+ private TestModel(final Boolean started, final String accountExternalKey, final UUID paymentId, final UUID paymentMethodId, final BigDecimal amount) {
+ isStarted = started;
+ this.accountExternalKey = accountExternalKey;
+ this.paymentId = paymentId;
+ this.paymentMethodId = paymentMethodId;
+ this.amount = amount;
+ }
+
+ public Boolean isStarted() {
+ return isStarted;
+ }
+
+ public String getAccountExternalKey() {
+ return accountExternalKey;
+ }
+
+ public UUID getPaymentId() {
+ return paymentId;
+ }
+
+ public UUID getPaymentMethodId() {
+ return paymentMethodId;
+ }
+
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ }
+
+
+ private static class TestMapper implements ResultSetMapper<TestModel> {
+
+ @Override
+ public TestModel map(final int index, final ResultSet r, final StatementContext ctx) throws SQLException {
+
+ final Boolean isStarted = r.getBoolean("is_started");
+ final String externalKey = r.getString("external_key");
+ final UUID paymentId = r.getString("payment_id") != null ? UUID.fromString(r.getString("payment_id")) : null;
+ final UUID paymentMethodId = r.getString("payment_method_id") != null ? UUID.fromString(r.getString("payment_method_id")) : null;
+ final BigDecimal amount = r.getBigDecimal("payment_amount");
+ return new TestModel(isStarted, externalKey, paymentId, paymentMethodId, amount);
+ }
+ }
+
+ private interface AwaitCallback {
+ boolean isSuccess();
+ }
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestOSGIBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestOSGIBase.java
index 437ebc0..661e490 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestOSGIBase.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/osgi/TestOSGIBase.java
@@ -23,6 +23,4 @@ import com.google.inject.Inject;
public class TestOSGIBase extends TestIntegrationBase {
- @Inject
- protected OSGIConfig config;
}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
index 6de9d54..4b67b61 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
@@ -46,6 +46,7 @@ import com.ning.billing.api.TestListenerStatus;
import com.ning.billing.beatrix.BeatrixTestSuiteWithEmbeddedDB;
import com.ning.billing.beatrix.bus.api.ExternalBus;
import com.ning.billing.beatrix.lifecycle.Lifecycle;
+import com.ning.billing.beatrix.osgi.SetupBundleWithAssertion;
import com.ning.billing.beatrix.util.AccountChecker;
import com.ning.billing.beatrix.util.EntitlementChecker;
import com.ning.billing.beatrix.util.InvoiceChecker;
@@ -82,6 +83,7 @@ import com.ning.billing.payment.api.PaymentMethodPlugin;
import com.ning.billing.payment.provider.MockPaymentProviderPlugin;
import com.ning.billing.util.api.TagUserApi;
import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.config.OSGIConfig;
import com.ning.billing.util.svcapi.account.AccountInternalApi;
import com.ning.billing.util.svcapi.junction.BlockingInternalApi;
import com.ning.billing.util.svcsapi.bus.BusService;
@@ -195,6 +197,10 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
@Inject
protected AccountInternalApi accountInternalApi;
+ @Inject
+ protected OSGIConfig osgiConfig;
+
+
protected TestApiListener busHandler;
private boolean isListenerFailed;
@@ -225,6 +231,9 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
g.injectMembers(this);
busHandler = new TestApiListener(this);
+ SetupBundleWithAssertion setupTest = new SetupBundleWithAssertion("whatever", osgiConfig, "whatever");
+ setupTest.cleanBundleInstallDir();
+
}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/osgi/SetupBundleWithAssertion.java b/beatrix/src/test/java/com/ning/billing/beatrix/osgi/SetupBundleWithAssertion.java
new file mode 100644
index 0000000..6436876
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/osgi/SetupBundleWithAssertion.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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
+ * 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 com.ning.billing.beatrix.osgi;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.URL;
+import java.nio.channels.FileChannel;
+
+import org.testng.Assert;
+
+import com.ning.billing.osgi.api.config.PluginConfig.PluginType;
+import com.ning.billing.osgi.api.config.PluginJavaConfig;
+import com.ning.billing.util.config.OSGIConfig;
+
+import com.google.common.io.Resources;
+
+public class SetupBundleWithAssertion {
+
+ private final String bundleName;
+ private final OSGIConfig config;
+ private final String killbillVersion;
+
+ public SetupBundleWithAssertion(final String bundleName, final OSGIConfig config, final String killbillVersion) {
+ this.bundleName = bundleName;
+ this.config = config;
+ this.killbillVersion = killbillVersion;
+ }
+
+ public void setupBundle() {
+
+ try {
+ // Retrieve PluginConfig info from classpath
+ // test bundle should have been exported under Beatrix resource by the maven maven-dependency-plugin
+ final PluginJavaConfig pluginConfig = extractBundleTestResource();
+ Assert.assertNotNull(pluginConfig);
+
+ // Create OSGI install bundle directory
+ setupDirectoryStructure(pluginConfig);
+
+ // Copy the jar
+ copyFile(new File(pluginConfig.getBundleJarPath()), new File(pluginConfig.getPluginVersionRoot().getAbsolutePath(), pluginConfig.getPluginVersionnedName() + ".jar"));
+
+ // Create the osgiConfig file
+ createConfigFile(pluginConfig);
+
+ } catch (IOException e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ public void cleanBundleInstallDir() {
+ final File rootDir = new File(config.getRootInstallationDir());
+ if (rootDir.exists()) {
+ deleteDirectory(rootDir, false);
+ }
+ }
+
+ private void createConfigFile(final PluginJavaConfig pluginConfig) throws IOException {
+
+ PrintStream printStream = null;
+ try {
+ final File configFile = new File(pluginConfig.getPluginVersionRoot(), config.getOSGIKillbillPropertyName());
+ configFile.createNewFile();
+ printStream = new PrintStream(new FileOutputStream(configFile));
+ printStream.print("pluginType=" + PluginType.NOTIFICATION);
+ } finally {
+ if (printStream != null) {
+ printStream.close();
+ }
+ }
+ }
+
+ private void setupDirectoryStructure(final PluginJavaConfig pluginConfig) {
+ cleanBundleInstallDir();
+ pluginConfig.getPluginVersionRoot().mkdirs();
+ }
+
+ private static void deleteDirectory(final File path, final boolean deleteParent) {
+ if (path == null) {
+ return;
+ }
+
+ if (path.exists()) {
+ final File[] files = path.listFiles();
+ if (files != null) {
+ for (final File f : files) {
+ if (f.isDirectory()) {
+ deleteDirectory(f, true);
+ }
+ f.delete();
+ }
+ }
+
+ if (deleteParent) {
+ path.delete();
+ }
+ }
+ }
+
+
+
+ private PluginJavaConfig extractBundleTestResource() {
+
+ final String resourceName = bundleName + "-" + killbillVersion + "-jar-with-dependencies.jar";
+ final URL resourceUrl = Resources.getResource(resourceName);
+ if (resourceUrl != null) {
+ final String[] parts = resourceUrl.getPath().split("/");
+ final String lastPart = parts[parts.length - 1];
+ if (lastPart.startsWith(bundleName)) {
+ return createPluginConfig(resourceUrl.getPath(), lastPart);
+ }
+ }
+ return null;
+
+ }
+
+ private PluginJavaConfig createPluginConfig(final String bundleTestResourcePath, final String fileName) {
+
+ return new PluginJavaConfig() {
+ @Override
+ public String getBundleJarPath() {
+ return bundleTestResourcePath;
+ }
+
+ @Override
+ public String getPluginName() {
+ return bundleName;
+ }
+
+ @Override
+ public PluginType getPluginType() {
+ return PluginType.PAYMENT;
+ }
+
+ @Override
+ public String getVersion() {
+ return killbillVersion;
+ }
+
+ @Override
+ public String getPluginVersionnedName() {
+ return bundleName + "-" + killbillVersion;
+ }
+
+ @Override
+ public File getPluginVersionRoot() {
+ final StringBuilder tmp = new StringBuilder(config.getRootInstallationDir());
+ tmp.append("/")
+ .append(PluginLanguage.JAVA.toString().toLowerCase())
+ .append("/")
+ .append(bundleName)
+ .append("/")
+ .append(killbillVersion);
+ final File result = new File(tmp.toString());
+ return result;
+ }
+
+ @Override
+ public PluginLanguage getPluginLanguage() {
+ return PluginLanguage.JAVA;
+ }
+ };
+ }
+
+ public static void copyFile(File sourceFile, File destFile) throws IOException {
+ if (!destFile.exists()) {
+ destFile.createNewFile();
+ }
+
+ FileChannel source = null;
+ FileChannel destination = null;
+
+ try {
+ source = new FileInputStream(sourceFile).getChannel();
+ destination = new FileOutputStream(destFile).getChannel();
+ destination.transferFrom(source, 0, source.size());
+ } finally {
+ if (source != null) {
+ source.close();
+ }
+ if (destination != null) {
+ destination.close();
+ }
+ }
+ }
+}
diff --git a/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIService.java b/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIService.java
index 068a91b..bacfd2d 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIService.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/DefaultOSGIService.java
@@ -202,7 +202,7 @@ public class DefaultOSGIService implements OSGIService {
}
private void pruneOSGICache() {
- final String path = osgiConfig.getOSGIBundleRootDir() + "/" + osgiConfig.getOSGIBundleCacheName();
+ final String path = osgiConfig.getOSGIBundleRootDir();
deleteUnderDirectory(new File(path));
}
diff --git a/osgi/src/main/java/com/ning/billing/osgi/pluginconf/PluginFinder.java b/osgi/src/main/java/com/ning/billing/osgi/pluginconf/PluginFinder.java
index acdba18..fd4963a 100644
--- a/osgi/src/main/java/com/ning/billing/osgi/pluginconf/PluginFinder.java
+++ b/osgi/src/main/java/com/ning/billing/osgi/pluginconf/PluginFinder.java
@@ -41,7 +41,6 @@ import com.ning.billing.util.config.OSGIConfig;
public class PluginFinder {
- private static final String INSTALATION_PROPERTIES = "killbill.properties";
private final Logger logger = LoggerFactory.getLogger(PluginFinder.class);
@@ -168,7 +167,7 @@ public class PluginFinder {
}
for (final File cur : files) {
- if (cur.isFile() && cur.getName().equals(INSTALATION_PROPERTIES)) {
+ if (cur.isFile() && cur.getName().equals(osgiConfig.getOSGIKillbillPropertyName())) {
props = readPluginConfigurationFile(cur);
}
if (props != null) {
osgi-bundles/pom.xml 1(+1 -0)
diff --git a/osgi-bundles/pom.xml b/osgi-bundles/pom.xml
index 3e1cb4e..797ba11 100644
--- a/osgi-bundles/pom.xml
+++ b/osgi-bundles/pom.xml
@@ -30,5 +30,6 @@
<module>hello</module>
<module>jruby</module>
<module>meter</module>
+ <module>test</module>
</modules>
</project>
osgi-bundles/test/pom.xml 154(+154 -0)
diff --git a/osgi-bundles/test/pom.xml b/osgi-bundles/test/pom.xml
new file mode 100644
index 0000000..66a0668
--- /dev/null
+++ b/osgi-bundles/test/pom.xml
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2010-2013 Ning, Inc.
+ ~
+ ~ Ning 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
+ ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ ~ License for the specific language governing permissions and limitations
+ ~ under the License.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-osgi-bundles</artifactId>
+ <version>0.1.54-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <artifactId>killbill-osgi-bundles-test</artifactId>
+ <name>Killbill billing platform: OSGI Test bundle</name>
+ <packaging>bundle</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>osgi-over-slf4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jdbi</groupId>
+ <artifactId>jdbi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>add-source</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src/test/java</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Activator>com.ning.billing.osgi.bundles.test.TestActivator</Bundle-Activator>
+ <Import-Package>
+ *;resolution:=optional
+ </Import-Package>
+ </instructions>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>assemble-killbill-osgi-bundles-test</id>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <shadedArtifactAttached>true</shadedArtifactAttached>
+ <shadedClassifierName>jar-with-dependencies</shadedClassifierName>
+ <filters>
+ <filter>
+ <artifact>${project.groupId}:${project.artifactId}</artifact>
+ </filter>
+ </filters>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-clean-plugin</artifactId>
+ <version>2.5</version>
+ <executions>
+ <execution>
+ <id>auto-clean</id>
+ <phase>install</phase>
+ <goals>
+ <goal>clean</goal>
+ </goals>
+ <configuration>
+ <excludeDefaultDirectories>true</excludeDefaultDirectories>
+ <filesets>
+ <fileset>
+ <directory>${project.build.directory}</directory>
+ <includes>
+ <include>${project.artifactId}-${project.version}.jar</include>
+ <include>${project.artifactId}-${project.version}-sources.jar</include>
+ </includes>
+ </fileset>
+ </filesets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/osgi-bundles/test/src/test/java/com/ning/billing/osgi/bundles/test/dao/TestDao.java b/osgi-bundles/test/src/test/java/com/ning/billing/osgi/bundles/test/dao/TestDao.java
new file mode 100644
index 0000000..fe63c4c
--- /dev/null
+++ b/osgi-bundles/test/src/test/java/com/ning/billing/osgi/bundles/test/dao/TestDao.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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
+ * 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 com.ning.billing.osgi.bundles.test.dao;
+
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.TransactionCallback;
+import org.skife.jdbi.v2.TransactionStatus;
+
+public class TestDao {
+
+ private final IDBI dbi;
+
+ public TestDao(final IDBI dbi) {
+ this.dbi = dbi;
+ }
+
+ public void createTable() {
+
+ dbi.inTransaction(new TransactionCallback<Object>() {
+ @Override
+ public Object inTransaction(final Handle conn, final TransactionStatus status) throws Exception {
+ conn.execute("DROP TABLE IF EXISTS test_bundle;");
+ conn.execute("CREATE TABLE test_bundle (" +
+ "record_id int(11) unsigned NOT NULL AUTO_INCREMENT, " +
+ "is_started bool DEFAULT false, " +
+ "is_logged bool DEFAULT false, " +
+ "external_key varchar(128) NULL, " +
+ "payment_id char(36) NULL," +
+ "payment_method_id char(36) NULL," +
+ "payment_amount decimal(10,4) NULL," +
+ "PRIMARY KEY(record_id)" +
+ ");");
+ return null;
+ }
+ });
+ }
+
+ public void insertStarted() {
+ dbi.inTransaction(new TransactionCallback<Object>() {
+ @Override
+ public Object inTransaction(final Handle conn, final TransactionStatus status) throws Exception {
+ conn.execute("INSERT INTO test_bundle (is_started) VALUES (1);");
+ return null;
+ }
+ });
+ }
+
+ public void insertAccountExternalKey(final String externalKey) {
+ dbi.inTransaction(new TransactionCallback<Object>() {
+ @Override
+ public Object inTransaction(final Handle conn, final TransactionStatus status) throws Exception {
+ conn.execute("UPDATE test_bundle SET external_key = '" + externalKey + "' WHERE record_id = 1;");
+ return null;
+ }
+ });
+ }
+
+ public void insertProcessedPayment(final UUID paymentId, final UUID paymentMethodId, final BigDecimal paymentAmount) {
+ dbi.inTransaction(new TransactionCallback<Object>() {
+ @Override
+ public Object inTransaction(final Handle conn, final TransactionStatus status) throws Exception {
+ conn.execute("UPDATE test_bundle SET payment_id = '" + paymentId.toString() +
+ "', payment_method_id = '" + paymentMethodId.toString() +
+ "', payment_amount = " + paymentAmount +
+ " WHERE record_id = 1;");
+ return null;
+ }
+ });
+ }
+}
diff --git a/osgi-bundles/test/src/test/java/com/ning/billing/osgi/bundles/test/TestActivator.java b/osgi-bundles/test/src/test/java/com/ning/billing/osgi/bundles/test/TestActivator.java
new file mode 100644
index 0000000..83576ca
--- /dev/null
+++ b/osgi-bundles/test/src/test/java/com/ning/billing/osgi/bundles/test/TestActivator.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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
+ * 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 com.ning.billing.osgi.bundles.test;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.UUID;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.log.LogService;
+import org.skife.jdbi.v2.DBI;
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.beatrix.bus.api.ExtBusEvent;
+import com.ning.billing.beatrix.bus.api.ExtBusEventType;
+import com.ning.billing.beatrix.bus.api.ExternalBus;
+import com.ning.billing.osgi.api.OSGIKillbill;
+import com.ning.billing.osgi.api.OSGIPluginProperties;
+import com.ning.billing.osgi.bundles.test.dao.TestDao;
+import com.ning.billing.payment.plugin.api.PaymentPluginApi;
+import com.ning.billing.util.callcontext.TenantContext;
+
+import com.google.common.eventbus.Subscribe;
+
+/**
+ * Test class used by Beatrix OSGI test to verify that:
+ * - "test" bundle is started
+ * - test bundle is able to make API call
+ * - test bundle is able to register a fake PaymentApi service
+ * - test bundle can use the DataSource from Killbill and write on disk
+ */
+public class TestActivator implements BundleActivator {
+
+ private OSGIKillbill osgiKillbill;
+ private volatile ServiceReference<OSGIKillbill> osgiKillbillReference;
+
+ private LogService logService;
+ private volatile ServiceReference<LogService> logServiceReference;
+
+
+ private volatile boolean isRunning;
+ private volatile ServiceRegistration paymentInfoPluginRegistration;
+
+ private TestDao testDao;
+
+ @Override
+ public void start(final BundleContext context) {
+
+ final String bundleName = context.getBundle().getSymbolicName();
+ System.out.println("TestActivator starting bundle = " + bundleName);
+
+ fetchOSGIKIllbill(context);
+ fetchLogService(context);
+
+ final IDBI dbi = new DBI(osgiKillbill.getDataSource());
+ testDao = new TestDao(dbi);
+ registerPaymentApi(context, testDao);
+
+ registerForKillbillEvents(context);
+
+ testDao.createTable();
+
+ testDao.insertStarted();
+
+ this.isRunning = true;
+ }
+
+ @Override
+ public void stop(final BundleContext context) {
+ this.isRunning = false;
+ releaseOSGIKIllbill(context);
+ this.osgiKillbill = null;
+ releaseLogService(context);
+ this.logService = null;
+ unregisterPlaymentPluginApi(context);
+ System.out.println("Good bye world from TestActivator!");
+ }
+
+ @Subscribe
+ public void handleKillbillEvent(final ExtBusEvent killbillEvent) {
+
+ logService.log(LogService.LOG_INFO, "Received external event " + killbillEvent.toString());
+
+ // Only looking at account creation
+ if (killbillEvent.getEventType() != ExtBusEventType.ACCOUNT_CREATION) {
+ return;
+ }
+
+ final TenantContext tenantContext = new TenantContext() {
+ @Override
+ public UUID getTenantId() {
+ return null;
+ }
+ };
+
+
+ try {
+ Account account = osgiKillbill.getAccountUserApi().getAccountById(killbillEvent.getAccountId(), tenantContext);
+ testDao.insertAccountExternalKey(account.getExternalKey());
+
+ } catch (AccountApiException e) {
+ logService.log(LogService.LOG_ERROR, e.getMessage());
+ }
+ }
+
+
+ private void registerForKillbillEvents(final BundleContext context) {
+ try {
+ final ExternalBus externalBus = osgiKillbill.getExternalBus();
+ externalBus.register(this);
+ } catch (Exception e) {
+ System.err.println("Error in TestActivator: " + e.getLocalizedMessage());
+ } finally {
+ }
+ }
+
+ private void fetchOSGIKIllbill(final BundleContext context) {
+ this.osgiKillbillReference = (ServiceReference<OSGIKillbill>) context.getServiceReference(OSGIKillbill.class.getName());
+ try {
+ this.osgiKillbill = context.getService(osgiKillbillReference);
+ } catch (Exception e) {
+ System.err.println("Error in TestActivator: " + e.getLocalizedMessage());
+ }
+ }
+
+ private void releaseOSGIKIllbill(final BundleContext context) {
+ if (osgiKillbillReference != null) {
+ context.ungetService(osgiKillbillReference);
+ }
+ }
+
+
+ private void fetchLogService(final BundleContext context) {
+ this.logServiceReference = (ServiceReference<LogService>) context.getServiceReference(LogService.class.getName());
+ try {
+ this.logService = context.getService(logServiceReference);
+ } catch (Exception e) {
+ System.err.println("Error in TestActivator: " + e.getLocalizedMessage());
+ }
+ }
+
+ private void releaseLogService(final BundleContext context) {
+ if (logServiceReference != null) {
+ context.ungetService(logServiceReference);
+ }
+ }
+
+ private void registerPaymentApi(final BundleContext context, final TestDao dao) {
+
+ final Dictionary props = new Hashtable();
+ props.put(OSGIPluginProperties.PLUGIN_NAME_PROP, "test");
+
+ this.paymentInfoPluginRegistration = context.registerService(PaymentPluginApi.class.getName(),
+ new TestPaymentPluginApi("test", dao), props);
+ }
+
+ private void unregisterPlaymentPluginApi(final BundleContext context) {
+ if (paymentInfoPluginRegistration != null) {
+ paymentInfoPluginRegistration.unregister();
+ paymentInfoPluginRegistration = null;
+ }
+ }
+}
diff --git a/osgi-bundles/test/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java b/osgi-bundles/test/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java
new file mode 100644
index 0000000..712c75e
--- /dev/null
+++ b/osgi-bundles/test/src/test/java/com/ning/billing/osgi/bundles/test/TestPaymentPluginApi.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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
+ * 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 com.ning.billing.osgi.bundles.test;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.osgi.bundles.test.dao.TestDao;
+import com.ning.billing.payment.api.PaymentMethodPlugin;
+import com.ning.billing.payment.plugin.api.PaymentInfoPlugin;
+import com.ning.billing.payment.plugin.api.PaymentMethodInfoPlugin;
+import com.ning.billing.payment.plugin.api.PaymentPluginApi;
+import com.ning.billing.payment.plugin.api.PaymentPluginApiException;
+import com.ning.billing.payment.plugin.api.RefundInfoPlugin;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.TenantContext;
+
+public class TestPaymentPluginApi implements PaymentPluginApi {
+
+ private final TestDao testDao;
+ private final String name;
+
+ public TestPaymentPluginApi(final String name, final TestDao testDao) {
+ this.testDao = testDao;
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public PaymentInfoPlugin processPayment(final UUID kbPaymentId, final UUID kbPaymentMethodId, final BigDecimal amount, final CallContext context) throws PaymentPluginApiException {
+ testDao.insertProcessedPayment(kbPaymentId, kbPaymentMethodId, amount);
+ return new PaymentInfoPlugin() {
+ @Override
+ public BigDecimal getAmount() {
+ return amount;
+ }
+ @Override
+ public DateTime getCreatedDate() {
+ return new DateTime();
+ }
+ @Override
+ public DateTime getEffectiveDate() {
+ return new DateTime();
+ }
+ @Override
+ public PaymentPluginStatus getStatus() {
+ return PaymentPluginStatus.PROCESSED;
+ }
+ @Override
+ public String getGatewayError() {
+ return null;
+ }
+ @Override
+ public String getGatewayErrorCode() {
+ return null;
+ }
+ };
+ }
+
+
+ @Override
+ public PaymentInfoPlugin getPaymentInfo(final UUID kbPaymentId, final TenantContext context) throws PaymentPluginApiException {
+ return null;
+ }
+
+ @Override
+ public RefundInfoPlugin processRefund(final UUID kbPaymentId, final BigDecimal refundAmount, final CallContext context) throws PaymentPluginApiException {
+ return null;
+ }
+
+ @Override
+ public void addPaymentMethod(final UUID kbPaymentMethodId, final PaymentMethodPlugin paymentMethodProps, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
+ }
+
+ @Override
+ public void deletePaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
+ }
+
+ @Override
+ public void setDefaultPaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
+ }
+
+ @Override
+ public List<PaymentMethodInfoPlugin> getPaymentMethods(final UUID kbAccountId, final boolean refreshFromGateway, final CallContext context) throws PaymentPluginApiException {
+ return null;
+ }
+
+ @Override
+ public void resetPaymentMethods(final List<PaymentMethodInfoPlugin> paymentMethods) throws PaymentPluginApiException {
+ }
+}
diff --git a/osgi-bundles/test/src/test/resources/ddl_test.sql b/osgi-bundles/test/src/test/resources/ddl_test.sql
new file mode 100644
index 0000000..e4bfa5d
--- /dev/null
+++ b/osgi-bundles/test/src/test/resources/ddl_test.sql
@@ -0,0 +1,10 @@
+/*! SET storage_engine=INNODB */;
+
+DROP TABLE IF EXISTS test_bundle;
+CREATE TABLE test_bundle (
+ record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+ is_started bool DEFAULT false,
+ is_logged bool DEFAULT false,
+ external_key varchar(128) NULL
+ PRIMARY KEY(record_id)
+);
pom.xml 8(+8 -0)
diff --git a/pom.xml b/pom.xml
index 6ec9b79..ce46a7d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -266,6 +266,11 @@
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
+ <artifactId>killbill-osgi-bundles-test</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
<artifactId>killbill-osgi-bundles-meter</artifactId>
<version>${project.version}</version>
</dependency>
@@ -645,7 +650,9 @@
<useManifestOnlyJar>false</useManifestOnlyJar>
<groups>fast,slow,mysql</groups>
<systemPropertyVariables>
+ <propertyName>propertyValue</propertyName>
<log4j.configuration>file:${project.basedir}/src/test/resources/log4j.xml</log4j.configuration>
+ <killbill.version>${project.version}</killbill.version>
</systemPropertyVariables>
</configuration>
</plugin>
@@ -715,6 +722,7 @@
</com.ning.billing.dbi.jdbc.url>
<file.encoding>UTF-8</file.encoding>
<user.timezone>GMT</user.timezone>
+ <killbill.version>${project.version}</killbill.version>
</systemPropertyVariables>
</configuration>
</plugin>
diff --git a/util/src/main/java/com/ning/billing/util/config/OSGIConfig.java b/util/src/main/java/com/ning/billing/util/config/OSGIConfig.java
index fc184fb..c135656 100644
--- a/util/src/main/java/com/ning/billing/util/config/OSGIConfig.java
+++ b/util/src/main/java/com/ning/billing/util/config/OSGIConfig.java
@@ -21,6 +21,10 @@ import org.skife.config.Default;
public interface OSGIConfig extends KillbillConfig {
+ @Config("killbill.osgi.bundle.property.name")
+ @Default("killbill.properties")
+ public String getOSGIKillbillPropertyName();
+
@Config("killbill.osgi.root.dir")
@Default("/var/tmp/felix")
public String getOSGIBundleRootDir();
@@ -48,6 +52,7 @@ public interface OSGIConfig extends KillbillConfig {
"com.ning.billing.osgi.api.config," +
"com.ning.billing.overdue," +
"com.ning.billing.payment.api," +
+ "com.ning.billing.payment.plugin.api," +
"com.ning.billing.tenant.api," +
"com.ning.billing.usage.api," +
"com.ning.billing.util.api," +