killbill-memoizeit
Changes
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsActivator.java 20(+20 -0)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java 2(+1 -1)
osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/http/AnalyticsServlet.java 185(+185 -0)
Details
diff --git a/osgi-bundles/bundles/analytics/pom.xml b/osgi-bundles/bundles/analytics/pom.xml
index 751ceb6..a7fa997 100644
--- a/osgi-bundles/bundles/analytics/pom.xml
+++ b/osgi-bundles/bundles/analytics/pom.xml
@@ -29,6 +29,14 @@
<packaging>bundle</packaging>
<dependencies>
<dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.datatype</groupId>
+ <artifactId>jackson-datatype-joda</artifactId>
+ </dependency>
+ <dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsActivator.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsActivator.java
index a167ff4..0433792 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsActivator.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsActivator.java
@@ -16,13 +16,23 @@
package com.ning.billing.osgi.bundles.analytics;
+import java.util.Hashtable;
+
+import javax.servlet.Servlet;
+import javax.servlet.http.HttpServlet;
+
import org.osgi.framework.BundleContext;
+import com.ning.billing.osgi.api.OSGIPluginProperties;
+import com.ning.billing.osgi.bundles.analytics.api.user.AnalyticsUserApi;
+import com.ning.billing.osgi.bundles.analytics.http.AnalyticsServlet;
import com.ning.killbill.osgi.libs.killbill.KillbillActivatorBase;
import com.ning.killbill.osgi.libs.killbill.OSGIKillbillEventDispatcher.OSGIKillbillEventHandler;
public class AnalyticsActivator extends KillbillActivatorBase {
+ public static final String PLUGIN_NAME = "killbill-analytics";
+
private OSGIKillbillEventHandler analyticsListener;
@Override
@@ -30,10 +40,20 @@ public class AnalyticsActivator extends KillbillActivatorBase {
super.start(context);
analyticsListener = new AnalyticsListener(logService, killbillAPI, dataSource);
+
+ final AnalyticsUserApi analyticsUserApi = new AnalyticsUserApi(logService, killbillAPI, dataSource);
+ final AnalyticsServlet analyticsServlet = new AnalyticsServlet(analyticsUserApi);
+ registerServlet(context, analyticsServlet);
}
@Override
public OSGIKillbillEventHandler getOSGIKillbillEventHandler() {
return analyticsListener;
}
+
+ private void registerServlet(final BundleContext context, final HttpServlet servlet) {
+ final Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put(OSGIPluginProperties.PLUGIN_NAME_PROP, PLUGIN_NAME);
+ registrar.registerService(context, Servlet.class, servlet, props);
+ }
}
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java
index 2b451c3..c04962f 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/AnalyticsListener.java
@@ -205,7 +205,7 @@ public class AnalyticsListener implements OSGIKillbillEventHandler {
@Override
public CallOrigin getCallOrigin() {
- return CallOrigin.EXTERNAL;
+ return CallOrigin.INTERNAL;
}
@Override
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/http/AnalyticsServlet.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/http/AnalyticsServlet.java
new file mode 100644
index 0000000..c025b8b
--- /dev/null
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/http/AnalyticsServlet.java
@@ -0,0 +1,185 @@
+/*
+ * 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.analytics.http;
+
+import java.io.IOException;
+import java.util.UUID;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
+import com.ning.billing.osgi.bundles.analytics.AnalyticsRefreshException;
+import com.ning.billing.osgi.bundles.analytics.api.BusinessSnapshot;
+import com.ning.billing.osgi.bundles.analytics.api.user.AnalyticsUserApi;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.UserType;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Objects;
+
+public class AnalyticsServlet extends HttpServlet {
+
+ private static final String QUERY_TENANT_ID = "tenantId";
+ private static final String HDR_CREATED_BY = "X-Killbill-CreatedBy";
+ private static final String HDR_REASON = "X-Killbill-Reason";
+ private static final String HDR_COMMENT = "X-Killbill-Comment";
+
+ private static final ObjectMapper mapper = ObjectMapperProvider.get();
+
+ private final AnalyticsUserApi analyticsUserApi;
+
+ public AnalyticsServlet(final AnalyticsUserApi analyticsUserApi) {
+ this.analyticsUserApi = analyticsUserApi;
+ }
+
+ @Override
+ protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+ final UUID kbAccountId = getKbAccountId(req, resp);
+ final CallContext context = createCallContext(req, resp);
+
+ final BusinessSnapshot businessSnapshot = analyticsUserApi.getBusinessSnapshot(kbAccountId, context);
+ resp.getOutputStream().write(mapper.writeValueAsBytes(businessSnapshot));
+ resp.setStatus(HttpServletResponse.SC_OK);
+ }
+
+ @Override
+ protected void doPut(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+ final UUID kbAccountId = getKbAccountId(req, resp);
+ final CallContext context = createCallContext(req, resp);
+
+ try {
+ analyticsUserApi.rebuildAnalyticsForAccount(kbAccountId, context);
+ resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
+ } catch (AnalyticsRefreshException e) {
+ resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+ }
+ }
+
+ private CallContext createCallContext(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
+ final String createdBy = Objects.firstNonNull(req.getHeader(HDR_CREATED_BY), req.getRemoteAddr());
+ final String reason = req.getHeader(HDR_REASON);
+ final String comment = Objects.firstNonNull(req.getHeader(HDR_COMMENT), req.getRequestURI());
+
+ final String tenantIdString = req.getParameter(QUERY_TENANT_ID);
+ if (tenantIdString == null) {
+ resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing tenantId query parameter in request: " + req.getPathInfo());
+ return null;
+ }
+
+ final UUID tenantId;
+ try {
+ tenantId = UUID.fromString(tenantIdString);
+ } catch (final IllegalArgumentException e) {
+ resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid UUID for tenant id: " + tenantIdString);
+ return null;
+ }
+
+ return new AnalyticsApiCallContext(createdBy, reason, comment, tenantId);
+ }
+
+ private UUID getKbAccountId(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
+ final String kbAccountIdString;
+ try {
+ kbAccountIdString = req.getPathInfo().substring(1, req.getPathInfo().length());
+ } catch (final StringIndexOutOfBoundsException e) {
+ resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Badly formed kb account id in request: " + req.getPathInfo());
+ return null;
+ }
+
+ final UUID kbAccountId;
+ try {
+ kbAccountId = UUID.fromString(kbAccountIdString);
+ } catch (final IllegalArgumentException e) {
+ resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid UUID for kb account id: " + kbAccountIdString);
+ return null;
+ }
+
+ return kbAccountId;
+ }
+
+ private static final class AnalyticsApiCallContext implements CallContext {
+
+ private final String createdBy;
+ private final String reason;
+ private final String comment;
+ private final UUID tenantId;
+ private final DateTime now;
+
+ private AnalyticsApiCallContext(final String createdBy,
+ final String reason,
+ final String comment,
+ final UUID tenantId) {
+ this.createdBy = createdBy;
+ this.reason = reason;
+ this.comment = comment;
+ this.tenantId = tenantId;
+
+ this.now = new DateTime(DateTimeZone.UTC);
+ }
+
+ @Override
+ public UUID getUserToken() {
+ return UUID.randomUUID();
+ }
+
+ @Override
+ public String getUserName() {
+ return createdBy;
+ }
+
+ @Override
+ public CallOrigin getCallOrigin() {
+ return CallOrigin.EXTERNAL;
+ }
+
+ @Override
+ public UserType getUserType() {
+ return UserType.ADMIN;
+ }
+
+ @Override
+ public String getReasonCode() {
+ return reason;
+ }
+
+ @Override
+ public String getComments() {
+ return comment;
+ }
+
+ @Override
+ public DateTime getCreatedDate() {
+ return now;
+ }
+
+ @Override
+ public DateTime getUpdatedDate() {
+ return now;
+ }
+
+ @Override
+ public UUID getTenantId() {
+ return tenantId;
+ }
+ }
+}
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/http/ObjectMapperProvider.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/http/ObjectMapperProvider.java
new file mode 100644
index 0000000..8a09357
--- /dev/null
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/http/ObjectMapperProvider.java
@@ -0,0 +1,37 @@
+/*
+ * 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.analytics.http;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.joda.JodaModule;
+
+public class ObjectMapperProvider {
+
+ private static final ObjectMapper objectMapper = new ObjectMapper();
+
+ static {
+ objectMapper.registerModule(new JodaModule());
+ objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ }
+
+ private ObjectMapperProvider() {}
+
+ public static ObjectMapper get() {
+ return objectMapper;
+ }
+}
diff --git a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessSnapshot.java b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessSnapshot.java
index 7952254..0cda5f2 100644
--- a/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessSnapshot.java
+++ b/osgi-bundles/bundles/analytics/src/test/java/com/ning/billing/osgi/bundles/analytics/api/TestBusinessSnapshot.java
@@ -37,6 +37,7 @@ import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessOverdueStatusMo
import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessSubscription;
import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessSubscriptionEvent;
import com.ning.billing.osgi.bundles.analytics.dao.model.BusinessSubscriptionTransitionModelDao;
+import com.ning.billing.osgi.bundles.analytics.http.ObjectMapperProvider;
import com.google.common.collect.ImmutableList;
@@ -158,5 +159,9 @@ public class TestBusinessSnapshot extends AnalyticsTestSuiteNoDB {
Assert.assertEquals(businessSnapshot.getBusinessTags().iterator().next(), businessTag);
Assert.assertEquals(businessSnapshot.getBusinessFields().size(), 1);
Assert.assertEquals(businessSnapshot.getBusinessFields().iterator().next(), businessField);
+
+ // We check we can write it out without exception - we can't deserialize it back (no annotation)
+ // but we don't care since the APIs are read-only for Analytics
+ final String asJson = ObjectMapperProvider.get().writeValueAsString(businessSnapshot);
}
}