Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Servlets improvements #86

Merged
merged 4 commits into from Nov 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
83 changes: 82 additions & 1 deletion README.md
Expand Up @@ -33,10 +33,13 @@ When configuring refreshes via stored procedures, make sure to bump the connecti
API
---

### Data

To retrieve all data for a given account:

```
curl -u admin:password \
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey:bob" \
-H "X-Killbill-ApiSecret:lazar" \
"http://127.0.0.1:8080/plugins/killbill-analytics/<ACCOUNT_ID>"
Expand Down Expand Up @@ -70,3 +73,81 @@ curl -v \
-H "X-Killbill-ApiSecret:lazar" \
"http://127.0.0.1:8080/plugins/killbill-analytics/accountId"
```

### Reports

To create a report:

```
curl -v \
-X POST \
-u admin:password \
-H "X-Killbill-ApiKey:bob" \
-H "X-Killbill-ApiSecret:lazar" \
-H 'Content-Type: application/json' \
-d '{"reportName": "report_accounts_summary",
"reportType": "COUNTERS",
"reportPrettyName": "Accounts summary",
"sourceTableName": "report_accounts_summary",
"refreshProcedureName": "refresh_report_accounts_summary",
"refreshFrequency": "HOURLY"}' \
"http://127.0.0.1:8080/plugins/killbill-analytics/reports"
```

To retrieve a report configuration by name:

```
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey:bob" \
-H "X-Killbill-ApiSecret:lazar" \
"http://127.0.0.1:8080/plugins/killbill-analytics/reports/report_accounts_summary"
```

To retrieve a report SQL query:

```
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey:bob" \
-H "X-Killbill-ApiSecret:lazar" \
"http://127.0.0.1:8080/plugins/killbill-analytics/reports?name=report_accounts_summary&startDate=2018-01-01&endDate=2018-05-01&sqlOnly=true"
```

To retrieve report data:

```
curl -v \
-u admin:password \
-H "X-Killbill-ApiKey:bob" \
-H "X-Killbill-ApiSecret:lazar" \
"http://127.0.0.1:8080/plugins/killbill-analytics/reports?name=report_accounts_summary&startDate=2018-01-01&endDate=2018-05-01&smooth=SUM_WEEKLY&format=csv"
```

### Healthcheck

Status:

```
curl -v \
-u admin:password \
"http://127.0.0.1:8080/plugins/killbill-analytics/healthcheck"
```

Put out of rotation:

```
curl -v \
-X DELETE \
-u admin:password \
"http://127.0.0.1:8080/plugins/killbill-analytics/healthcheck"
```

Put in rotation:

```
curl -v \
-X PUT \
-u admin:password \
"http://127.0.0.1:8080/plugins/killbill-analytics/healthcheck"
```
67 changes: 63 additions & 4 deletions pom.xml
Expand Up @@ -40,6 +40,10 @@
<url>https://github.com/killbill/killbill-analytics-plugin/issues</url>
</issueManagement>
<dependencies>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
Expand Down Expand Up @@ -100,7 +104,12 @@
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>test</scope>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
Expand Down Expand Up @@ -296,16 +305,66 @@
<!-- Optional resolution because exported by the Felix system bundle -->
<!-- sun.misc and javax.management are required for Metrics (notification queue) -->
<Import-Package>
org.killbill.billing.account.api;
org.killbill.billing.catalog.api;
org.killbill.billing.invoice.api;
org.killbill.billing.entitlement.api;
org.killbill.billing.notification.api;
org.killbill.billing.notification.plugin.api;
org.killbill.billing.notification.plugin;
org.killbill.billing.osgi.api;
org.killbill.billing.osgi.api.config;
org.killbill.billing.payment.api;
org.killbill.billing.payment.plugin.api;
org.killbill.billing.control.plugin.api;
org.killbill.billing.tenant.api;
org.killbill.billing.usage.api;
org.killbill.billing.util.api;
org.killbill.billing.currency.plugin.api;
org.killbill.billing.currency.api;
org.killbill.billing.security.api;
org.xml.sax.helpers;
org.xml.sax;
org.w3c.dom;
org.w3c.dom.ls,
org.killbill.billing.osgi.api;
org.killbill.billing.osgi.api.config;
org.w3c.dom.ls;
sun.misc;
javax.net.ssl;
javax.management;
javax.jws;
javax.jws.soap;
javax.annotation;
javax.activation;
javax.xml.soap;
javax.xml.ws;
javax.xml.ws.spi;
javax.xml.ws.handler.soap;
javax.xml.ws.handler;
javax.xml.ws.http;
javax.xml.ws.soap;
javax.xml.ws.wsaddressing;
javax.xml.stream;
javax.xml.stream.events;
javax.xml.stream.util;
javax.xml.bind.annotation.adapters;
javax.xml.bind;
javax.xml.bind.helpers;
javax.xml.bind.annotation;
javax.xml.bind.attachment;
javax.xml.datatype;
javax.xml.namespace;
javax.xml.parsers;
javax.xml.transform;
javax.xml.transform.sax;
javax.xml.transform.dom;
javax.xml.transform.stream;
javax.xml.xpath;
javax.naming.directory;
javax.naming.event;
javax.naming.ldap;
javax.naming.spi;
javax.naming;
org.osgi.service.log;
version="[0,3)",
*;resolution:=optional
</Import-Package>
</instructions>
Expand Down
Expand Up @@ -35,11 +35,15 @@
import org.killbill.billing.plugin.analytics.api.user.AnalyticsUserApi;
import org.killbill.billing.plugin.analytics.core.AnalyticsHealthcheck;
import org.killbill.billing.plugin.analytics.dao.BusinessDBIProvider;
import org.killbill.billing.plugin.analytics.http.ServletRouter;
import org.killbill.billing.plugin.analytics.http.AnalyticsHealthcheckResource;
import org.killbill.billing.plugin.analytics.http.AnalyticsAccountResource;
import org.killbill.billing.plugin.analytics.http.ReportsResource;
import org.killbill.billing.plugin.analytics.reports.ReportsConfiguration;
import org.killbill.billing.plugin.analytics.reports.ReportsUserApi;
import org.killbill.billing.plugin.analytics.reports.scheduler.JobsScheduler;
import org.killbill.billing.plugin.api.notification.PluginConfigurationEventHandler;
import org.killbill.billing.plugin.core.resources.jooby.PluginApp;
import org.killbill.billing.plugin.core.resources.jooby.PluginAppBuilder;
import org.killbill.bus.dao.BusEventModelDao;
import org.killbill.clock.Clock;
import org.killbill.commons.embeddeddb.EmbeddedDB;
Expand All @@ -58,20 +62,16 @@

public class AnalyticsActivator extends KillbillActivatorBase {

private static final Logger logger = LoggerFactory.getLogger(AnalyticsActivator.class);

public static final String PLUGIN_NAME = "killbill-analytics";
public static final String ANALYTICS_QUEUE_SERVICE = "AnalyticsService";

private static final Logger logger = LoggerFactory.getLogger(AnalyticsActivator.class);
private final MetricRegistry metricRegistry = new MetricRegistry();
private AnalyticsConfigurationHandler analyticsConfigurationHandler;
private AnalyticsListener analyticsListener;
private JobsScheduler jobsScheduler;
private ReportsUserApi reportsUserApi;

private Clock killbillClock;

private final MetricRegistry metricRegistry = new MetricRegistry();

@Override
public void start(final BundleContext context) throws Exception {
super.start(context);
Expand All @@ -93,7 +93,6 @@ public void start(final BundleContext context) throws Exception {
dbi.registerMapper(new LowerToCamelBeanMapperFactory(BusEventModelDao.class));
dbi.registerMapper(new LowerToCamelBeanMapperFactory(NotificationEventModelDao.class));


final DefaultNotificationQueueService notificationQueueService = new DefaultNotificationQueueService(dbi, killbillClock, config, metricRegistry);

analyticsConfigurationHandler = new AnalyticsConfigurationHandler(PLUGIN_NAME, roOSGIkillbillAPI, logService);
Expand All @@ -110,13 +109,28 @@ public void start(final BundleContext context) throws Exception {
final AnalyticsUserApi analyticsUserApi = new AnalyticsUserApi(roOSGIkillbillAPI, dataSource, configProperties, executor, killbillClock, analyticsConfigurationHandler);
reportsUserApi = new ReportsUserApi(roOSGIkillbillAPI, dataSource, configProperties, dbEngine, reportsConfiguration, jobsScheduler);

final ServletRouter servletRouter = new ServletRouter(analyticsUserApi, reportsUserApi);
registerServlet(context, servletRouter);
final AnalyticsHealthcheck healthcheck = new AnalyticsHealthcheck(analyticsListener, jobsScheduler);
registerHealthcheck(context, healthcheck);

final PluginApp pluginApp = new PluginAppBuilder(PLUGIN_NAME,
killbillAPI,
logService,
dataSource,
clock,
configProperties).withRouteClass(AnalyticsHealthcheckResource.class)
.withRouteClass(ReportsResource.class)
.withRouteClass(AnalyticsAccountResource.class) // Needs to be last (to avoid matching /healthcheck or /reports)!
.withService(analyticsUserApi)
.withService(reportsUserApi)
.withService(clock)
.withService(healthcheck)
.build();
final HttpServlet httpServlet = PluginApp.createServlet(pluginApp);
registerServlet(context, httpServlet);

registerHandlers();
registerHealthcheck(context, new AnalyticsHealthcheck(analyticsListener, jobsScheduler));
}


@Override
public void stop(final BundleContext context) throws Exception {
if (analyticsListener != null) {
Expand Down
Expand Up @@ -402,7 +402,7 @@ protected Long getInvoicePaymentRecordId(final UUID invoicePaymentId, final Tena
//

protected Collection<Payment> getPaymentsWithPluginInfoByAccountId(final UUID accountId, final TenantContext context) throws AnalyticsRefreshException {
PaymentApiException error;
Exception error;

final PaymentApi paymentApi = getPaymentUserApi();
try {
Expand All @@ -418,14 +418,23 @@ protected Collection<Payment> getPaymentsWithPluginInfoByAccountId(final UUID ac
error = e1;
}
}
} catch (final RuntimeException e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you have in mind with catching this RuntimeException - are we trying to handle bug related exception or if not what is the scenario?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the payment plugin isn't well behaved and throws a RuntimeException (bug, misconfiguration, etc.), I think we still want to go ahead and refresh the Analytics data (without the plugin details).

// Plugin exception?
error = e;
try {
final List<Payment> accountPayments = paymentApi.getAccountPayments(accountId, false, false, PLUGIN_PROPERTIES, context);
logger.warn(e.getMessage() + ". Analytics tables will be missing plugin specific information");
return accountPayments;
} catch (final PaymentApiException ignored) {
}
}

logger.warn("Error retrieving payments for account id {}", accountId, error);
throw new AnalyticsRefreshException(error);
}

protected List<PaymentMethod> getPaymentMethodsForAccount(final UUID accountId, final TenantContext context) throws AnalyticsRefreshException {
PaymentApiException error;
Exception error;

final PaymentApi paymentApi = getPaymentUserApi();
try {
Expand All @@ -441,6 +450,15 @@ protected List<PaymentMethod> getPaymentMethodsForAccount(final UUID accountId,
error = e1;
}
}
} catch (final RuntimeException e) {
// Plugin exception?
error = e;
try {
final List<PaymentMethod> accountPaymentMethods = paymentApi.getAccountPaymentMethods(accountId, true, false, PLUGIN_PROPERTIES, context);
logger.warn(e.getMessage() + ". Analytics tables will be missing plugin specific information");
return accountPaymentMethods;
} catch (final PaymentApiException ignored) {
}
}

logger.warn("Error retrieving payment methods for account id {}", accountId, error);
Expand Down