killbill-aplcache
Changes
bin/db-helper 2(+2 -0)
bin/start-server 33(+33 -0)
jaxrs/pom.xml 97(+97 -0)
jaxrs/src/test/resources/log4j.xml 36(+36 -0)
pom.xml 35(+31 -4)
server/pom.xml 470(+470 -0)
server/src/main/jetty-config/etc/webdefault.xml 186(+186 -0)
server/src/main/jetty-config/ning-jetty-conf.xml 122(+122 -0)
server/src/main/resources/catalog-demo.xml 641(+641 -0)
server/src/main/resources/log4j.xml 63(+63 -0)
server/src/main/webapp/WEB-INF/web.xml 43(+43 -0)
server/src/test/resources/log4j.xml 36(+36 -0)
Details
bin/db-helper 2(+2 -0)
diff --git a/bin/db-helper b/bin/db-helper
new file mode 100644
index 0000000..3134267
--- /dev/null
+++ b/bin/db-helper
@@ -0,0 +1,2 @@
+#!/bin/bash -eu
+
bin/start-server 33(+33 -0)
diff --git a/bin/start-server b/bin/start-server
new file mode 100755
index 0000000..8b87f3d
--- /dev/null
+++ b/bin/start-server
@@ -0,0 +1,33 @@
+#! /usr/bin/env bash
+
+HERE=`cd \`dirname $0\`; pwd`
+TOP=$HERE/..
+SERVER=$TOP/server
+
+PROPERTIES="$SERVER/src/main/resources/killbill-server.properties"
+
+#DEBUG_OPTS_ECLIPSE=
+DEBUG_OPTS_ECLIPSE=" -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=12345 "
+OPTS_ECLIPSE=" -Xmx2048m -XX:+UseConcMarkSweepGC -XX:MaxPermSize=128m "
+
+LOG="$SERVER/src/main/resources/log4j.xml"
+
+PORT=8080
+
+OPTS=
+for PROP in `cat $PROPERTIES | grep =`; do
+ K=`echo $PROP | awk ' BEGIN {FS="="} { print $1 }'`
+ V=`echo $PROP | awk 'BEGIN {FS="="} { print $2 }'`
+ OPTS="$OPTS -D$K=$V"
+done
+
+
+START_CMD="mvn $OPTS -Dlog4j.configuration=file://$LOG -Dning.jmx.http.port=$PORT -Dxn.host.external.port=$PORT -DjettyPort=$PORT -Dxn.server.port=$PORT jetty:run"
+
+echo "Starting IRS:"
+echo "$START_CMD"
+
+export MAVEN_OPTS=" -Duser.timezone=UTC $OPTS_ECLIPSE $DEBUG_OPTS_ECLIPSE"
+
+cd $SERVER
+$START_CMD
jaxrs/pom.xml 97(+97 -0)
diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
new file mode 100644
index 0000000..0701aa2
--- /dev/null
+++ b/jaxrs/pom.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Copyright 2010-2011 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</artifactId>
+ <version>0.1.8-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <artifactId>killbill-jaxrs</artifactId>
+ <name>killbill-jaxrs</name>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ <!-- WHY DO WE NEED VESRION HERE ?? -->
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.inject</groupId>
+ <artifactId>guice</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.skife.config</groupId>
+ <artifactId>config-magic</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-jaxrs</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java
new file mode 100644
index 0000000..da10dab
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.joda.time.DateTimeZone;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.catalog.api.Currency;
+
+public class AccountJson {
+
+ // Missing city, locale, postalCode from https://home.ninginc.com:8443/display/REVINFRA/Killbill+1.0+APIs
+
+ private final String acountId;
+ private final String name;
+ private final Integer length;
+ private final String externalKey;
+ private final String email;
+ private final Integer billCycleDay;
+ private final String currency;
+ private final String paymentProvider;
+ private final String timeZone;
+ private final String address1;
+ private final String address2;
+ private final String company;
+ private final String state;
+ private final String country;
+ private final String phone;
+
+
+ public AccountJson(Account account) {
+ this.acountId = account.getId().toString();
+ this.name = account.getName();
+ this.length = account.getFirstNameLength();
+ this.externalKey = account.getExternalKey();
+ this.email = account.getEmail();
+ this.billCycleDay = account.getBillCycleDay();
+ this.currency = account.getCurrency().toString();
+ this.paymentProvider = account.getPaymentProviderName();
+ this.timeZone = account.getTimeZone().toString();
+ this.address1 = account.getAddress1();
+ this.address2 = account.getAddress2();
+ this.company = account.getCompanyName();
+ this.state = account.getStateOrProvince();
+ this.country = account.getCountry();
+ this.phone = account.getPhone();
+ }
+
+ public AccountData toAccountData() {
+ return new AccountData() {
+ @Override
+ public DateTimeZone getTimeZone() {
+ return (timeZone != null) ? DateTimeZone.forID(timeZone) : null;
+ }
+ @Override
+ public String getStateOrProvince() {
+ return state;
+ }
+ @Override
+ public String getPostalCode() {
+ return null;
+ }
+ @Override
+ public String getPhone() {
+ return phone;
+ }
+ @Override
+ public String getPaymentProviderName() {
+ return paymentProvider;
+ }
+ @Override
+ public String getName() {
+ return name;
+ }
+ @Override
+ public String getLocale() {
+ return null;
+ }
+ @Override
+ public int getFirstNameLength() {
+ return length;
+ }
+ @Override
+ public String getExternalKey() {
+ return externalKey;
+ }
+ @Override
+ public String getEmail() {
+ return email;
+ }
+ @Override
+ public Currency getCurrency() {
+ Currency result = (currency != null) ? Currency.valueOf(currency) : Currency.USD;
+ return result;
+ }
+ @Override
+ public String getCountry() {
+ return country;
+ }
+ @Override
+ public String getCompanyName() {
+ return company;
+ }
+ @Override
+ public String getCity() {
+ return null;
+ }
+ @Override
+ public int getBillCycleDay() {
+ return billCycleDay;
+ }
+ @Override
+ public String getAddress2() {
+ return address2;
+ }
+ @Override
+ public String getAddress1() {
+ return address1;
+ }
+ };
+ }
+
+
+ @JsonCreator
+ public AccountJson(@JsonProperty("account_id") String acountId,
+ @JsonProperty("name") String name,
+ @JsonProperty("first_name_length") Integer length,
+ @JsonProperty("external_key") String externalKey,
+ @JsonProperty("email") String email,
+ @JsonProperty("billing_day") Integer billCycleDay,
+ @JsonProperty("currency") String currency,
+ @JsonProperty("payment_provider") String paymentProvider,
+ @JsonProperty("timezone") String timeZone,
+ @JsonProperty("address1") String address1,
+ @JsonProperty("address2") String address2,
+ @JsonProperty("company") String company,
+ @JsonProperty("state") String state,
+ @JsonProperty("country") String country,
+ @JsonProperty("phone") String phone) {
+ super();
+ this.acountId = acountId;
+ this.name = name;
+ this.length = length;
+ this.externalKey = externalKey;
+ this.email = email;
+ this.billCycleDay = billCycleDay;
+ this.currency = currency;
+ this.paymentProvider = paymentProvider;
+ this.timeZone = timeZone;
+ this.address1 = address1;
+ this.address2 = address2;
+ this.company = company;
+ this.state = state;
+ this.country = country;
+ this.phone = phone;
+ }
+
+ public String getAcountId() {
+ return acountId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Integer getLength() {
+ return length;
+ }
+
+ public String getExternalKey() {
+ return externalKey;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public Integer getBillCycleDay() {
+ return billCycleDay;
+ }
+
+ public String getCurrency() {
+ return currency;
+ }
+
+ public String getPaymentProvider() {
+ return paymentProvider;
+ }
+
+ public String getTimeZone() {
+ return timeZone;
+ }
+
+ public String getAddress1() {
+ return address1;
+ }
+
+ public String getAddress2() {
+ return address2;
+ }
+
+ public String getCompany() {
+ return company;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+ }
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJson.java
new file mode 100644
index 0000000..226c365
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJson.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonView;
+
+public class BundleJson {
+
+ @JsonView(BundleTimelineViews.Base.class)
+ private final String bundleId;
+
+ @JsonView(BundleTimelineViews.Base.class)
+ private final String accountId;
+
+ @JsonView(BundleTimelineViews.Base.class)
+ private final String externalKey;
+
+ @JsonView(BundleTimelineViews.Timeline.class)
+ private final List<SubscriptionJson> subscriptions;
+
+ @JsonCreator
+ public BundleJson(@JsonProperty("bundle_id") String bundleId,
+ @JsonProperty("account_id") String accountId,
+ @JsonProperty("external_key") String externalKey,
+ @JsonProperty("subscriptions") List<SubscriptionJson> subscriptions) {
+ super();
+ this.bundleId = bundleId;
+ this.accountId = accountId;
+ this.externalKey = externalKey;
+ this.subscriptions = subscriptions;
+ }
+
+ public String getBundleId() {
+ return bundleId;
+ }
+
+ public String getAccountId() {
+ return accountId;
+ }
+
+ public String getExternalKey() {
+ return externalKey;
+ }
+
+ public List<SubscriptionJson> getSubscriptions() {
+ return subscriptions;
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineJson.java
new file mode 100644
index 0000000..61761a7
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineJson.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonView;
+
+public class BundleTimelineJson {
+
+ @JsonView(BundleTimelineViews.Timeline.class)
+ private final String viewId;
+
+ @JsonView(BundleTimelineViews.Timeline.class)
+ private final BundleJson bundle;
+
+ @JsonView(BundleTimelineViews.ReadTimeline.class)
+ private final List<PaymentJson> payments;
+
+ @JsonView(BundleTimelineViews.ReadTimeline.class)
+ private final List<InvoiceJson> invoices;
+
+ @JsonView(BundleTimelineViews.WriteTimeline.class)
+ private final String resonForChange;
+
+ @JsonCreator
+ public BundleTimelineJson(@JsonProperty("view_id") String viewId,
+ @JsonProperty("bundle") BundleJson bundle,
+ @JsonProperty("payments") List<PaymentJson> payments,
+ @JsonProperty("invoices") List<InvoiceJson> invoices,
+ @JsonProperty("reason_for_change") String reason) {
+ this.viewId = viewId;
+ this.bundle = bundle;
+ this.payments = payments;
+ this.invoices = invoices;
+ this.resonForChange = reason;
+ }
+
+ public String getViewId() {
+ return viewId;
+ }
+
+ public BundleJson getBundle() {
+ return bundle;
+ }
+
+ public List<PaymentJson> getPayments() {
+ return payments;
+ }
+
+ public List<InvoiceJson> getInvoices() {
+ return invoices;
+ }
+
+ public String getResonForChange() {
+ return resonForChange;
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineViews.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineViews.java
new file mode 100644
index 0000000..020764e
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineViews.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+
+public class BundleTimelineViews {
+ static class Base {};
+ static class Timeline extends Base {};
+ static class ReadTimeline extends Timeline {};
+ static class WriteTimeline extends Timeline {};
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJson.java
new file mode 100644
index 0000000..b13bdee
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJson.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.math.BigDecimal;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.joda.time.DateTime;
+
+public class InvoiceJson {
+
+ private final BigDecimal amount;
+ private final String invoiceId;
+ private final DateTime requestedDate;
+ private final String invoiceNumber;
+ private final BigDecimal balance;
+
+ @JsonCreator
+ public InvoiceJson(@JsonProperty("amount") BigDecimal amount,
+ @JsonProperty("invoice_id") String invoiceId,
+ @JsonProperty("requested_dt") DateTime requestedDate,
+ @JsonProperty("invoice_number") String invoiceNumber,
+ @JsonProperty("balance") BigDecimal balance) {
+ super();
+ this.amount = amount;
+ this.invoiceId = invoiceId;
+ this.requestedDate = requestedDate;
+ this.invoiceNumber = invoiceNumber;
+ this.balance = balance;
+ }
+
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ public String getInvoiceId() {
+ return invoiceId;
+ }
+
+ public DateTime getRequestedDate() {
+ return requestedDate;
+ }
+
+ public String getInvoiceNumber() {
+ return invoiceNumber;
+ }
+
+ public BigDecimal getBalance() {
+ return balance;
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJson.java
new file mode 100644
index 0000000..1f932d4
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJson.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.math.BigDecimal;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.joda.time.DateTime;
+
+import com.ning.billing.util.clock.DefaultClock;
+
+public class PaymentJson {
+
+ private final BigDecimal paidAmount;
+ private final String invoiceId;
+ private final String paymentId;
+ private final DateTime requestedDate;
+ private final DateTime effectiveDate;
+ private final String status;
+
+ @JsonCreator
+ public PaymentJson(@JsonProperty("paid_amount") BigDecimal paidAmount,
+ @JsonProperty("invoice_id") String invoiceId,
+ @JsonProperty("payment_id") String paymentId,
+ @JsonProperty("requested_dt") DateTime requestedDate,
+ @JsonProperty("effective_dt") DateTime effectiveDate,
+ @JsonProperty("status") String status) {
+ super();
+ this.paidAmount = paidAmount;
+ this.invoiceId = invoiceId;
+ this.paymentId = paymentId;
+ this.requestedDate = DefaultClock.toUTCDateTime(requestedDate);
+ this.effectiveDate = DefaultClock.toUTCDateTime(effectiveDate);
+ this.status = status;
+ }
+
+ public BigDecimal getPaidAmount() {
+ return paidAmount;
+ }
+
+ public String getInvoiceId() {
+ return invoiceId;
+ }
+
+ public String getPaymentId() {
+ return paymentId;
+ }
+
+ public DateTime getRequestedDate() {
+ return DefaultClock.toUTCDateTime(requestedDate);
+ }
+
+ public DateTime getEffectiveDate() {
+ return DefaultClock.toUTCDateTime(effectiveDate);
+ }
+
+ public String getStatus() {
+ return status;
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJson.java
new file mode 100644
index 0000000..a08a305
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJson.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonView;
+import org.joda.time.DateTime;
+
+import com.ning.billing.util.clock.DefaultClock;
+
+public class SubscriptionJson {
+
+ @JsonView(BundleTimelineViews.Base.class)
+ private final String subscriptionId;
+
+ @JsonView(BundleTimelineViews.Base.class)
+ private final String bundleId;
+
+ @JsonView(BundleTimelineViews.Base.class)
+ private final String productName;
+
+ @JsonView(BundleTimelineViews.Base.class)
+ private final String productCategory;
+
+ @JsonView(BundleTimelineViews.Base.class)
+ private final String billingPeriod;
+
+ @JsonView(BundleTimelineViews.Base.class)
+ private final String priceList;
+
+ @JsonView(BundleTimelineViews.ReadTimeline.class)
+ private final List<SubscriptionReadEventJson> events;
+
+ @JsonView(BundleTimelineViews.WriteTimeline.class)
+ private final List<SubscriptionDeletedEventJson> deletedEvents;
+
+ @JsonView(BundleTimelineViews.WriteTimeline.class)
+ private final List<SubscriptionNewEventJson> newEvents;
+
+
+ public static class SubscriptionReadEventJson extends SubscriptionBaseEventJson {
+
+ @JsonView(BundleTimelineViews.Timeline.class)
+ private final String eventId;
+
+ @JsonView(BundleTimelineViews.Timeline.class)
+ private final DateTime effectiveDate;
+
+ @JsonCreator
+ public SubscriptionReadEventJson(@JsonProperty("event_id") String eventId,
+ @JsonProperty("billing_period") String billingPeriod,
+ @JsonProperty("requested_dt") DateTime requestedDate,
+ @JsonProperty("effective_dt") DateTime effectiveDate,
+ @JsonProperty("product") String product,
+ @JsonProperty("price_list") String priceList,
+ @JsonProperty("event_type") String eventType,
+ @JsonProperty("phase") String phase) {
+ super(billingPeriod, requestedDate, product, priceList, eventType, phase);
+ this.eventId = eventId;
+ this.effectiveDate = effectiveDate;
+ }
+
+ public String getEventId() {
+ return eventId;
+ }
+
+ public DateTime getEffectiveDate() {
+ return DefaultClock.toUTCDateTime(effectiveDate);
+ }
+
+ @Override
+ public String toString() {
+ return "SubscriptionReadEventJson [eventId=" + eventId
+ + ", effectiveDate=" + effectiveDate
+ + ", getBillingPeriod()=" + getBillingPeriod()
+ + ", getRequestedDate()=" + getRequestedDate()
+ + ", getProduct()=" + getProduct() + ", getPriceList()="
+ + getPriceList() + ", getEventType()=" + getEventType()
+ + ", getPhase()=" + getPhase() + ", getClass()="
+ + getClass() + ", hashCode()=" + hashCode()
+ + ", toString()=" + super.toString() + "]";
+ }
+ }
+
+ public static class SubscriptionDeletedEventJson extends SubscriptionReadEventJson {
+ @JsonCreator
+ public SubscriptionDeletedEventJson(@JsonProperty("event_id") String eventId,
+ @JsonProperty("billing_period") String billingPeriod,
+ @JsonProperty("requested_dt") DateTime requestedDate,
+ @JsonProperty("effective_dt") DateTime effectiveDate,
+ @JsonProperty("product") String product,
+ @JsonProperty("price_list") String priceList,
+ @JsonProperty("event_type") String eventType,
+ @JsonProperty("phase") String phase) {
+ super(eventId, billingPeriod, requestedDate, effectiveDate, product, priceList, eventType, phase);
+
+ }
+ }
+
+
+ public static class SubscriptionNewEventJson extends SubscriptionBaseEventJson {
+ @JsonCreator
+ public SubscriptionNewEventJson(@JsonProperty("billing_period") String billingPeriod,
+ @JsonProperty("requested_dt") DateTime requestedDate,
+ @JsonProperty("product") String product,
+ @JsonProperty("price_list") String priceList,
+ @JsonProperty("event_type") String eventType,
+ @JsonProperty("phase") String phase) {
+ super(billingPeriod, requestedDate, product, priceList, eventType, phase);
+ }
+
+ @Override
+ public String toString() {
+ return "SubscriptionNewEventJson [getBillingPeriod()="
+ + getBillingPeriod() + ", getRequestedDate()="
+ + getRequestedDate() + ", getProduct()=" + getProduct()
+ + ", getPriceList()=" + getPriceList()
+ + ", getEventType()=" + getEventType() + ", getPhase()="
+ + getPhase() + ", getClass()=" + getClass()
+ + ", hashCode()=" + hashCode() + ", toString()="
+ + super.toString() + "]";
+ }
+ }
+
+ public static class SubscriptionBaseEventJson {
+
+ @JsonView(BundleTimelineViews.Timeline.class)
+ private final String billingPeriod;
+
+ @JsonView(BundleTimelineViews.Timeline.class)
+ private final DateTime requestedDate;
+
+
+ @JsonView(BundleTimelineViews.Timeline.class)
+ private final String product;
+
+ @JsonView(BundleTimelineViews.Timeline.class)
+ private final String priceList;
+
+ @JsonView(BundleTimelineViews.Timeline.class)
+ private final String eventType;
+
+ @JsonView(BundleTimelineViews.Timeline.class)
+ private final String phase;
+
+ @JsonCreator
+ public SubscriptionBaseEventJson(@JsonProperty("billing_period") String billingPeriod,
+ @JsonProperty("requested_dt") DateTime requestedDate,
+ @JsonProperty("product") String product,
+ @JsonProperty("price_list") String priceList,
+ @JsonProperty("event_type") String eventType,
+ @JsonProperty("phase") String phase) {
+ super();
+ this.billingPeriod = billingPeriod;
+ this.requestedDate = DefaultClock.toUTCDateTime(requestedDate);
+ this.product = product;
+ this.priceList = priceList;
+ this.eventType = eventType;
+ this.phase = phase;
+ }
+
+ public String getBillingPeriod() {
+ return billingPeriod;
+ }
+
+ public DateTime getRequestedDate() {
+ return DefaultClock.toUTCDateTime(requestedDate);
+ }
+
+ public String getProduct() {
+ return product;
+ }
+
+ public String getPriceList() {
+ return priceList;
+ }
+
+ public String getEventType() {
+ return eventType;
+ }
+
+ public String getPhase() {
+ return phase;
+ }
+ }
+
+
+ @JsonCreator
+ public SubscriptionJson(@JsonProperty("subscription_id") String subscriptionId,
+ @JsonProperty("bundle_id") String bundleId,
+ @JsonProperty("product_name") String productName,
+ @JsonProperty("product_category") String productCategory,
+ @JsonProperty("billing_period") String billingPeriod,
+ @JsonProperty("price_list") String priceList,
+ @JsonProperty("events") List<SubscriptionReadEventJson> events,
+ @JsonProperty("new_events") List<SubscriptionNewEventJson> newEvents,
+ @JsonProperty("deleted_events") List<SubscriptionDeletedEventJson> deletedEvents) {
+ super();
+ this.subscriptionId = subscriptionId;
+ this.bundleId = bundleId;
+ this.productName = productName;
+ this.productCategory = productCategory;
+ this.billingPeriod = billingPeriod;
+ this.priceList = priceList;
+ this.events = events;
+ this.deletedEvents = deletedEvents;
+ this.newEvents = newEvents;
+ }
+
+ public String getSubscriptionId() {
+ return subscriptionId;
+ }
+
+ public String getBundleId() {
+ return bundleId;
+ }
+
+ public String getProductName() {
+ return productName;
+ }
+
+ public String getProductCategory() {
+ return productCategory;
+ }
+
+ public String getBillingPeriod() {
+ return billingPeriod;
+ }
+
+ public String getPriceList() {
+ return priceList;
+ }
+
+ public List<SubscriptionReadEventJson> getEvents() {
+ return events;
+ }
+
+ public List<SubscriptionNewEventJson> getNewEvents() {
+ return newEvents;
+ }
+
+ public List<SubscriptionDeletedEventJson> getDeletedEvents() {
+ return deletedEvents;
+ }
+
+ @Override
+ public String toString() {
+ return "SubscriptionJson [subscriptionId=" + subscriptionId
+ + ", bundleId=" + bundleId + ", productName=" + productName
+ + ", productCategory=" + productCategory + ", billingPeriod="
+ + billingPeriod + ", priceList=" + priceList + ", events="
+ + events + ", deletedEvents=" + deletedEvents + ", newEvents="
+ + newEvents + "]";
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
new file mode 100644
index 0000000..d34d0ac
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import java.net.URI;
+import java.util.UUID;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.Response.Status;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.jaxrs.json.AccountJson;
+
+
+@Singleton
+@Path("/1.0/account")
+public class AccountResource {
+
+ private static final Logger log = LoggerFactory.getLogger(AccountResource.class);
+
+ private final AccountUserApi accountApi;
+
+ @Inject
+ public AccountResource(AccountUserApi accountApi) {
+ this.accountApi = accountApi;
+ }
+
+ @GET
+ @Path("/{accountId:\\w+}")
+ @Produces(APPLICATION_JSON)
+ public Response getAccount(@PathParam("accountId") String accountId) {
+ Account account = accountApi.getAccountById(UUID.fromString(accountId));
+ if (account == null) {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+ AccountJson json = new AccountJson(account);
+ return Response.status(Status.OK).entity(json).build();
+ }
+
+ @GET
+ @Produces(APPLICATION_JSON)
+ public Response getAccountByKey(@QueryParam("externalKey") String externalKey) {
+ Account account = null;
+ if (externalKey != null) {
+ account = accountApi.getAccountByKey(externalKey);
+ }
+ if (account == null) {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+ AccountJson json = new AccountJson(account);
+ return Response.status(Status.OK).entity(json).build();
+ }
+
+ @POST
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response createAccount(AccountJson json) {
+
+ try {
+ AccountData data = json.toAccountData();
+ final Account account = accountApi.createAccount(data, null, null);
+ URI uri = UriBuilder.fromPath(account.getId().toString()).build();
+ Response.ResponseBuilder ri = Response.created(uri);
+ return ri.entity(new Object() {
+ public URI getUri() {
+ return UriBuilder.fromResource(AccountResource.class).path(AccountResource.class, "getAccount").build(account.getId());
+ }
+ }).build();
+ } catch (AccountApiException e) {
+ log.info(String.format("Failed to create account %s", json), e);
+ return Response.status(Status.BAD_REQUEST).build();
+ }
+ }
+
+ @PUT
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ @Path("/{accountId:\\w+}")
+ public Response updateAccount(AccountJson json, @PathParam("accountId") String accountId) {
+ try {
+ AccountData data = json.toAccountData();
+ accountApi.updateAccount(accountId, data);
+ return Response.status(Status.NO_CONTENT).build();
+ } catch (AccountApiException e) {
+ log.info(String.format("Failed to update account %s with %s", accountId, json), e);
+ return Response.status(Status.BAD_REQUEST).build();
+ }
+ }
+
+ // Not supported
+ @DELETE
+ @Path("/{accountId:\\w+}")
+ @Produces(APPLICATION_JSON)
+ public Response cancelAccount(@PathParam("accountId") String accountId) {
+ /*
+ try {
+ accountApi.cancelAccount(accountId);
+ return Response.status(Status.NO_CONTENT).build();
+ } catch (AccountApiException e) {
+ log.info(String.format("Failed to cancel account %s", accountId), e);
+ return Response.status(Status.BAD_REQUEST).build();
+ }
+ */
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountTimeline.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountTimeline.java
new file mode 100644
index 0000000..e154f85
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountTimeline.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+public class AccountTimeline {
+
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
new file mode 100644
index 0000000..07a7517
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import com.ning.billing.jaxrs.json.BundleJson;
+
+@Path("/1.0/bundle")
+public class BundleResource {
+
+ @GET
+ @Path("/{bundleId:\\w+}")
+ @Produces(APPLICATION_JSON)
+ public Response getBundle(@PathParam("bundleId") String bundleId) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @GET
+ @Produces(APPLICATION_JSON)
+ public Response getBundleByKey(@QueryParam("externalKey") String externalKey) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @POST
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response createBundle(BundleJson bundle) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleTimelineResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleTimelineResource.java
new file mode 100644
index 0000000..93a1f23
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleTimelineResource.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+
+@Path("/1.0/timeline/bundle")
+public class BundleTimelineResource {
+
+ @GET
+ @Path("/{bundleId:\\w+}")
+ @Produces(APPLICATION_JSON)
+ public Response getBundleTimeline(@PathParam("bundleId") String bundleId) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @POST
+ @Produces(APPLICATION_JSON)
+ @Consumes(APPLICATION_JSON)
+ @Path("/{bundleId:\\w+}/repair")
+ public Response repairBundleTineline(BundleTimelineResource bundle,
+ @PathParam("bundleId") String bundleId) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargedbackResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargedbackResource.java
new file mode 100644
index 0000000..5d3168b
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargedbackResource.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+public class ChargedbackResource {
+
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/CreditResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/CreditResource.java
new file mode 100644
index 0000000..076dbff
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/CreditResource.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+public class CreditResource {
+
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
new file mode 100644
index 0000000..1db336e
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import com.ning.billing.jaxrs.json.InvoiceJson;
+
+
+
+@Path("/1.0/invoice")
+public class InvoiceResource {
+
+
+ @GET
+ @Produces(APPLICATION_JSON)
+ public Response getInvoices(@QueryParam("accountId") String accountId) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @GET
+ @Path("/{invoiceId:\\w+}")
+ @Produces(APPLICATION_JSON)
+ public Response getInvoice(@PathParam("invoiceId") String accountId) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @POST
+ @Path("/{accountId:\\w+}")
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response createFutureInvoice(InvoiceJson invoice,
+ @PathParam("accountId") String accountId,
+ @QueryParam("targetDate") String targetDate) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
new file mode 100644
index 0000000..f68874d
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import com.ning.billing.jaxrs.json.PaymentJson;
+
+
+@Path("/1.0/payment")
+public class PaymentResource {
+
+
+ @GET
+ @Path("/{invoiceId:\\w+}")
+ @Produces(APPLICATION_JSON)
+ public Response getPayments(@PathParam("invoiceId") String invoiceId) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @GET
+ @Path("/account/{accountId:\\w+}")
+ @Produces(APPLICATION_JSON)
+ public Response getAllPayments(@PathParam("accountId") String accountId) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @POST
+ @Produces(APPLICATION_JSON)
+ @Consumes(APPLICATION_JSON)
+ @Path("/{invoiceId:\\w+}")
+ public Response createInstantPayment(PaymentJson payment,
+ @PathParam("invoiceId") String invoiceId,
+ @QueryParam("last4CC") String last4CC,
+ @QueryParam("nameOnCC") String nameOnCC) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/RefundResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/RefundResource.java
new file mode 100644
index 0000000..05acf58
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/RefundResource.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+public class RefundResource {
+
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
new file mode 100644
index 0000000..ee3c200
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
+import com.ning.billing.jaxrs.json.SubscriptionJson;
+
+@Path("/1.0/subscription")
+public class SubscriptionResource {
+
+ @GET
+ @Path("/{subscriptionId:\\w+}")
+ @Produces(APPLICATION_JSON)
+ public Response getSubscription(@PathParam("subscriptionId") String subscriptionId) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @POST
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON)
+ public Response createSubscription(SubscriptionJson subscription,
+ @QueryParam("requestedDate") String requestedDate) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @PUT
+ @Produces(APPLICATION_JSON)
+ @Consumes(APPLICATION_JSON)
+ @Path("/{subscriptionId:\\w+}")
+ public Response changeSubscriptionPlan(SubscriptionJson subscription,
+ @PathParam("subscriptionId") String subscriptionId,
+ @QueryParam("requestedDate") String requestedDate) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @PUT
+ @Path("/{subscriptionId:\\w+}/uncancel")
+ @Produces(APPLICATION_JSON)
+ public Response uncancelSubscriptionPlan(@PathParam("subscriptionId") String subscriptionId) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @DELETE
+ @Path("/{subscriptionId:\\w+}")
+ @Produces(APPLICATION_JSON)
+ public Response cancelSubscriptionPlan(@PathParam("subscriptionId") String subscriptionId,
+ @QueryParam("requestedDate") String requestedDate) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/TagResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/TagResource.java
new file mode 100644
index 0000000..cc19095
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/TagResource.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.resources;
+
+public class TagResource {
+
+}
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestJsonViews.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestJsonViews.java
new file mode 100644
index 0000000..7e28130
--- /dev/null
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestJsonViews.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.io.StringWriter;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectWriter;
+import org.codehaus.jackson.map.SerializationConfig;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.ning.billing.jaxrs.json.SubscriptionJson.SubscriptionDeletedEventJson;
+import com.ning.billing.jaxrs.json.SubscriptionJson.SubscriptionNewEventJson;
+import com.ning.billing.jaxrs.json.SubscriptionJson.SubscriptionReadEventJson;
+
+public class TestJsonViews {
+
+
+ public static final Logger log = LoggerFactory.getLogger(TestJsonViews.class);
+
+ private ObjectMapper objectMapper;
+
+ @BeforeClass(groups="fast")
+ public void setup() {
+ objectMapper = new ObjectMapper().configure(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION, false);
+ objectMapper.disable(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS);
+ }
+
+
+
+ @Test(groups="fast")
+ public void testSubscriptionBaseView() {
+ testSubscriptionView(BundleTimelineViews.Base.class);
+ }
+
+ @Test(groups="fast")
+ public void testSubscriptionTimelineView() {
+ testSubscriptionView(BundleTimelineViews.ReadTimeline.class);
+ }
+
+ private void testSubscriptionView(Class<? extends BundleTimelineViews.Base> viewClass) {
+ try {
+
+ SubscriptionJson obj = buildSubscriptionReadEventJson();
+
+ ObjectWriter objWriter = objectMapper.writerWithView(viewClass);
+
+ Writer writer = new StringWriter();
+ objWriter.writeValue(writer, obj);
+ String baseJson = writer.toString();
+
+ log.info(baseJson);
+
+ SubscriptionJson objFromJson = objectMapper.readValue(baseJson, SubscriptionJson.class);
+
+ log.info(objFromJson.toString());
+
+ if (viewClass.equals(BundleTimelineViews.Base.class)) {
+ Assert.assertNull(objFromJson.getEvents());
+ } else {
+ Assert.assertNotNull(objFromJson.getEvents());
+ }
+
+ writer = new StringWriter();
+ objWriter.writeValue(writer, objFromJson);
+ String newBaseJson = writer.toString();
+
+ Assert.assertEquals(newBaseJson, baseJson);
+
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ @Test(groups="fast")
+ public void testBundleReadTimelineJson() {
+ testBundleTimelineJson(BundleTimelineViews.ReadTimeline.class);
+ }
+
+ @Test(groups="fast")
+ public void testBundleWriteTimelineJson() {
+ testBundleTimelineJson(BundleTimelineViews.WriteTimeline.class);
+ }
+
+ private void testBundleTimelineJson(Class<? extends BundleTimelineViews.Base> viewClass) {
+
+ final boolean readTimeline = viewClass.equals(BundleTimelineViews.ReadTimeline.class);
+ try {
+
+ BundleTimelineJson obj = buildBundleTimelineJson(readTimeline);
+
+ ObjectWriter objWriter = objectMapper.writerWithView(viewClass);
+
+ Writer writer = new StringWriter();
+ objWriter.writeValue(writer, obj);
+ String baseJson = writer.toString();
+
+ log.info(baseJson);
+
+ BundleTimelineJson objFromJson = objectMapper.readValue(baseJson, BundleTimelineJson.class);
+
+ log.info(objFromJson.toString());
+
+ Assert.assertNotNull(objFromJson.getViewId());
+ Assert.assertNotNull(objFromJson.getBundle());
+
+ BundleJson bundle = objFromJson.getBundle();
+ Assert.assertNotNull(bundle.getBundleId());
+ Assert.assertNotNull(bundle.getAccountId());
+ Assert.assertNotNull(bundle.getExternalKey());
+ Assert.assertNotNull(bundle.getSubscriptions());
+
+ List<SubscriptionJson> subscriptions = bundle.getSubscriptions();
+ Assert.assertEquals(subscriptions.size(), 1);
+ SubscriptionJson sub = subscriptions.get(0);
+ Assert.assertNotNull(sub.getBundleId());
+ Assert.assertNotNull(sub.getBillingPeriod());
+ Assert.assertNotNull(sub.getPriceList());
+ Assert.assertNotNull(sub.getProductCategory());
+ Assert.assertNotNull(sub.getProductName());
+ Assert.assertNotNull(sub.getSubscriptionId());
+
+ List<SubscriptionReadEventJson> events = sub.getEvents();
+ List<SubscriptionDeletedEventJson> deletedEvents = sub.getDeletedEvents();
+ List<SubscriptionNewEventJson> newEvents = sub.getNewEvents();
+
+ if (viewClass.equals(BundleTimelineViews.WriteTimeline.class)) {
+ Assert.assertNull(objFromJson.getPayments());
+ Assert.assertNull(objFromJson.getInvoices());
+ Assert.assertNull(objFromJson.getInvoices());
+
+ Assert.assertNull(events);
+ Assert.assertEquals(newEvents.size(), 1);
+ for (SubscriptionNewEventJson cur : newEvents) {
+ Assert.assertNotNull(cur.getRequestedDate());
+ Assert.assertNotNull(cur.getEventType());
+ Assert.assertNotNull(cur.getBillingPeriod());
+ Assert.assertNotNull(cur.getPhase());
+ Assert.assertNotNull(cur.getPriceList());
+ Assert.assertNotNull(cur.getProduct());
+ }
+
+
+ Assert.assertEquals(deletedEvents.size(), 1);
+ for (SubscriptionDeletedEventJson cur : deletedEvents) {
+ Assert.assertNotNull(cur.getEventId());
+ Assert.assertNotNull(cur.getEffectiveDate());
+ Assert.assertNotNull(cur.getRequestedDate());
+ Assert.assertNotNull(cur.getEventType());
+ Assert.assertNotNull(cur.getBillingPeriod());
+ Assert.assertNotNull(cur.getPhase());
+ Assert.assertNotNull(cur.getPriceList());
+ Assert.assertNotNull(cur.getProduct());
+ }
+
+
+ Assert.assertNotNull(objFromJson.getResonForChange());
+
+ } else if (viewClass.equals(BundleTimelineViews.ReadTimeline.class)) {
+ Assert.assertNotNull(objFromJson.getPayments());
+ Assert.assertNotNull(objFromJson.getInvoices());
+ Assert.assertNotNull(objFromJson.getInvoices());
+
+ Assert.assertNull(newEvents);
+ Assert.assertNull(deletedEvents);
+ Assert.assertEquals(events.size(), 2);
+ for (SubscriptionReadEventJson cur : events) {
+ Assert.assertNotNull(cur.getEventId());
+ Assert.assertNotNull(cur.getEffectiveDate());
+ Assert.assertNotNull(cur.getRequestedDate());
+ Assert.assertNotNull(cur.getEventType());
+ Assert.assertNotNull(cur.getBillingPeriod());
+ Assert.assertNotNull(cur.getPhase());
+ Assert.assertNotNull(cur.getPriceList());
+ Assert.assertNotNull(cur.getProduct());
+ }
+
+ Assert.assertNull(objFromJson.getResonForChange());
+ } else {
+ Assert.fail("View of no interest");
+ }
+
+ writer = new StringWriter();
+ objWriter.writeValue(writer, objFromJson);
+ String newBaseJson = writer.toString();
+
+ Assert.assertEquals(newBaseJson, baseJson);
+
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+
+ }
+
+ private BundleTimelineJson buildBundleTimelineJson(boolean readTimeline) {
+
+ final String reason = "whatever";
+ final String viewId = "view-123356";
+ final BundleJson bundle = buildBundle(readTimeline);
+ final List<PaymentJson> payments = new LinkedList<PaymentJson>();
+ payments.add(buildPaymentJson());
+
+ final List<InvoiceJson> invoices = new LinkedList<InvoiceJson>();
+ invoices.add(buildInvoiceJson());
+ return new BundleTimelineJson(viewId, bundle, payments, invoices, reason);
+ }
+
+
+ private BundleJson buildBundle(boolean readTimeline) {
+ final String bundleId = UUID.randomUUID().toString();
+ final String accountId = UUID.randomUUID().toString();
+ final String externalKey = "bozo-the-sioux";
+ final List<SubscriptionJson> subscriptions = new LinkedList<SubscriptionJson>();
+ subscriptions.add(readTimeline ? buildSubscriptionReadEventJson() : buildSubscriptionWriteEventJson());
+ return new BundleJson(bundleId, accountId, externalKey, subscriptions);
+ }
+ private PaymentJson buildPaymentJson() {
+
+ final BigDecimal paidAmount = new BigDecimal(128.56);
+ final String invoiceId = UUID.randomUUID().toString();
+ final String paymentId = UUID.randomUUID().toString();
+ final DateTime requestedDate = new DateTime();
+ final DateTime effectiveDate = requestedDate;
+ final String status = "Success";
+ return new PaymentJson(paidAmount, invoiceId, paymentId, requestedDate, effectiveDate, status);
+ }
+
+ private InvoiceJson buildInvoiceJson() {
+ final BigDecimal amount = new BigDecimal(128.56);
+ final BigDecimal balance = new BigDecimal(0.0);
+ final String invoiceId = UUID.randomUUID().toString();
+ final String invoiceNumber = "INV-00012";
+ final DateTime requestedDate = new DateTime();
+ return new InvoiceJson(amount, invoiceId, requestedDate, invoiceNumber, balance);
+ }
+
+ private SubscriptionJson buildSubscriptionReadEventJson() {
+
+ final List<SubscriptionReadEventJson> events = new LinkedList<SubscriptionReadEventJson>();
+
+ final String eventId1 = UUID.randomUUID().toString();
+ final String productName1 = "gold";
+ final String billingPeriod1 = "monthly";
+ final DateTime requestedDate1 = new DateTime();
+ final DateTime effectiveDate1 = requestedDate1;
+ final String priceList1 = "default";
+ final String eventType1 = "CREATE";
+ final String phase1 = "TRIAL";
+ SubscriptionReadEventJson ev1 = new SubscriptionReadEventJson(eventId1, billingPeriod1, requestedDate1, effectiveDate1, productName1, priceList1, eventType1, phase1);
+ events.add(ev1);
+
+ final String eventId2 = UUID.randomUUID().toString();
+ final String productName2 = "gold";
+ final String billingPeriod2 = "monthly";
+ final DateTime requestedDate2 = new DateTime();
+ final DateTime effectiveDate2 = requestedDate2;
+ final String priceList2 = "default";
+ final String eventType2 = "PHASE";
+ final String phase2 = "EVERGREEN";
+ SubscriptionReadEventJson ev2 = new SubscriptionReadEventJson(eventId2, billingPeriod2, requestedDate2, effectiveDate2, productName2, priceList2, eventType2, phase2);
+ events.add(ev2);
+
+
+ final String subscriptionId = UUID.randomUUID().toString();
+ final String bundleId = UUID.randomUUID().toString();
+ final String productName = productName2;
+ final String productCategory = "classic";
+ final String billingPeriod = billingPeriod2;
+ final String priceList = priceList2;
+
+ SubscriptionJson obj = new SubscriptionJson(subscriptionId, bundleId, productName, productCategory, billingPeriod, priceList, events, null, null);
+ return obj;
+ }
+
+
+ private SubscriptionJson buildSubscriptionWriteEventJson() {
+
+ final List<SubscriptionNewEventJson> newEvents = new LinkedList<SubscriptionNewEventJson>();
+
+ final String eventId1 = UUID.randomUUID().toString();
+ final String productName1 = "gold";
+ final String billingPeriod1 = "monthly";
+ final DateTime requestedDate1 = new DateTime();
+ final DateTime effectiveDate1 = requestedDate1;
+ final String priceList1 = "default";
+ final String eventType1 = "CREATE";
+ final String phase1 = "TRIAL";
+ SubscriptionNewEventJson ev1 = new SubscriptionNewEventJson(billingPeriod1, requestedDate1, productName1, priceList1, eventType1, phase1);
+ newEvents.add(ev1);
+
+ final List<SubscriptionDeletedEventJson> deletedEvents = new LinkedList<SubscriptionDeletedEventJson>();
+ final String eventId2 = UUID.randomUUID().toString();
+ final String productName2 = "gold";
+ final String billingPeriod2 = "monthly";
+ final DateTime requestedDate2 = new DateTime();
+ final DateTime effectiveDate2 = requestedDate2;
+ final String priceList2 = "default";
+ final String eventType2 = "PHASE";
+ final String phase2 = "EVERGREEN";
+ SubscriptionDeletedEventJson ev2 = new SubscriptionDeletedEventJson(eventId2, billingPeriod2, requestedDate2, effectiveDate2, productName2, priceList2, eventType2, phase2);
+ deletedEvents.add(ev2);
+
+
+ final String subscriptionId = UUID.randomUUID().toString();
+ final String bundleId = UUID.randomUUID().toString();
+ final String productName = productName2;
+ final String productCategory = "classic";
+ final String billingPeriod = billingPeriod2;
+ final String priceList = priceList2;
+
+ SubscriptionJson obj = new SubscriptionJson(subscriptionId, bundleId, productName, productCategory, billingPeriod, priceList, null, newEvents, deletedEvents);
+ return obj;
+ }
+
+
+}
jaxrs/src/test/resources/log4j.xml 36(+36 -0)
diff --git a/jaxrs/src/test/resources/log4j.xml b/jaxrs/src/test/resources/log4j.xml
new file mode 100644
index 0000000..512d2dc
--- /dev/null
+++ b/jaxrs/src/test/resources/log4j.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2010-2011 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.
+ -->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+ <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%p %d{ISO8601} %X{trace} %t %c %m%n"/>
+ </layout>
+ </appender>
+
+
+ <logger name="com.ning.billing.jaxrs">
+ <level value="info"/>
+ </logger>
+
+ <root>
+ <priority value="info"/>
+ <appender-ref ref="stdout"/>
+ </root>
+</log4j:configuration>
pom.xml 35(+31 -4)
diff --git a/pom.xml b/pom.xml
index c0c46a2..65cc464 100644
--- a/pom.xml
+++ b/pom.xml
@@ -47,9 +47,31 @@
<module>invoice</module>
<module>payment</module>
<module>util</module>
+ <module>jaxrs</module>
+ <module>server</module>
</modules>
<dependencyManagement>
<dependencies>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-beatrix</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-analytics</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-jaxrs</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>com.ning.billing</groupId>
<artifactId>killbill-api</artifactId>
@@ -64,6 +86,11 @@
</dependency>
<dependency>
<groupId>com.ning.billing</groupId>
+ <artifactId>killbill-server</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
<artifactId>killbill-account</artifactId>
<version>${project.version}</version>
</dependency>
@@ -137,17 +164,17 @@
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
- <version>1.9.2</version>
+ <version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
- <version>1.9.2</version>
+ <version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
- <version>1.9.2</version>
+ <version>1.9.4</version>
</dependency>
<dependency>
<groupId>com.jolbox</groupId>
@@ -203,7 +230,7 @@
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
- <version>2.5</version>
+ <version>2.6</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
server/pom.xml 470(+470 -0)
diff --git a/server/pom.xml b/server/pom.xml
new file mode 100644
index 0000000..7653948
--- /dev/null
+++ b/server/pom.xml
@@ -0,0 +1,470 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Copyright 2010-2011 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</artifactId>
+ <version>0.1.8-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <artifactId>killbill-server</artifactId>
+ <name>killbill-server</name>
+ <packaging>war</packaging>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <skeleton.version>0.0.20</skeleton.version>
+ </properties>
+
+ <dependencies>
+
+
+
+
+
+ <!-- NOT in master POM; include version as well -->
+
+ <dependency>
+ <groupId>org.weakref</groupId>
+ <artifactId>jmxutils</artifactId>
+ <version>1.10</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.yammer.metrics</groupId>
+ <artifactId>metrics-core</artifactId>
+ <version>2.0.0-BETA17</version>
+ </dependency>
+ <dependency>
+ <groupId>com.yammer.metrics</groupId>
+ <artifactId>metrics-guice</artifactId>
+ <version>2.0.0-BETA17</version>
+ </dependency>
+
+
+ <dependency>
+ <groupId>com.google.inject.extensions</groupId>
+ <artifactId>guice-servlet</artifactId>
+ <version>3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-server</artifactId>
+ <version>1.10</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.jersey.contribs</groupId>
+ <artifactId>jersey-guice</artifactId>
+ <version>1.10</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Do we want to depend on skeleton -->
+ <dependency>
+ <groupId>com.ning.jetty</groupId>
+ <artifactId>ning-service-skeleton-base</artifactId>
+ <version>${skeleton.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.jetty</groupId>
+ <artifactId>ning-service-skeleton-log4j</artifactId>
+ <version>${skeleton.version}</version>
+ <classifier>selfcontained</classifier>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- JETTY -->
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-http</artifactId>
+ <version>7.5.1.v20110908</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
+ <version>7.5.1.v20110908</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-util</artifactId>
+ <version>7.5.1.v20110908</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-server</artifactId>
+ <version>7.5.1.v20110908</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-deploy</artifactId>
+ <version>7.5.1.v20110908</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-jmx</artifactId>
+ <version>7.5.1.v20110908</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-xml</artifactId>
+ <version>7.5.1.v20110908</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.6.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>jcl-over-slf4j</artifactId>
+ <version>1.6.3</version>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.6.3</version>
+ </dependency>
+
+
+ <!-- FROM MASTER POM / LIBRARY -->
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-jaxrs</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-beatrix</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-entitlement</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-invoice</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-payment</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-catalog</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ning.billing</groupId>
+ <artifactId>killbill-analytics</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.inject</groupId>
+ <artifactId>guice</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency><!-- Needed by jmxutils -->
+ <groupId>com.google.inject.extensions</groupId>
+ <artifactId>guice-multibindings</artifactId>
+ <scope>compile</scope>
+ </dependency>
+
+ <!-- SCOPE RUNTIME FROM MAIN POM; DO WE NEED IT ? -->
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.antlr</groupId>
+ <artifactId>stringtemplate</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.skife.config</groupId>
+ <artifactId>config-magic</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <!-- Ning specific -->
+ <id>pulse-build</id>
+ <properties>
+ <jettyWebroot>root</jettyWebroot>
+ </properties>
+ <activation>
+ <property>
+ <name>env</name>
+ <value>pulse-build</value>
+ </property>
+ </activation>
+ <dependencies>
+ <dependency><!-- For LogLevelCounterAppender -->
+ <groupId>com.ning.jetty</groupId>
+ <artifactId>ning-service-skeleton-log4j</artifactId>
+ <version>${skeleton.version}</version>
+ <classifier>selfcontained</classifier>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>ning.core</groupId>
+ <artifactId>galaxy-deploy-scripts</artifactId>
+ <version>13.0.4</version>
+ <type>tar.gz</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>ning.galaxy</groupId>
+ <artifactId>galaxy-library</artifactId>
+ <version>2.4.1</version>
+ <type>tar.gz</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>ning.jetty</groupId>
+ <artifactId>ning-jetty-distribution</artifactId>
+ <version>7.5.1-NING-1.0.1</version>
+ <type>tar.gz</type>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>ning.maven</groupId>
+ <artifactId>default-assemblies</artifactId>
+ <version>2.1.0</version>
+ </dependency>
+ </dependencies>
+ <executions>
+ <execution>
+ <id>assemble-irs</id>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <appendAssemblyId>false</appendAssemblyId>
+ <descriptorRefs>
+ <descriptorRef>default-jetty7-war-assembly</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.ning.maven.plugins</groupId>
+ <artifactId>maven-dependency-versions-check-plugin</artifactId>
+ <version>2.0.2</version>
+ <configuration>
+ <failBuildInCaseOfConflict>true</failBuildInCaseOfConflict>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <!-- To make eclipse happy -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.5</version>
+ </plugin>
+ <plugin>
+ <groupId>com.ning.maven.plugins</groupId>
+ <artifactId>maven-duplicate-finder-plugin</artifactId>
+ <version>1.0.2</version>
+ <configuration>
+ <failBuildInCaseOfConflict>false</failBuildInCaseOfConflict>
+ <!-- That's for Jetty -->
+ <ignoredResources>
+ <ignoredResource>about.html</ignoredResource>
+ </ignoredResources>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.3</version>
+ <executions>
+ <execution>
+ <id>analyze</id>
+ <goals>
+ <goal>analyze-only</goal>
+ </goals>
+ <configuration>
+ <ignoreNonCompile>true</ignoreNonCompile>
+ <failOnWarning>false</failOnWarning>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.2.1</version>
+ <configuration>
+ <mavenExecutorId>forked-path</mavenExecutorId>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.scm</groupId>
+ <artifactId>maven-scm-provider-gitexe</artifactId>
+ <version>1.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.plexus</groupId>
+ <artifactId>plexus-utils</artifactId>
+ <version>1.5.9</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <plugin>
+ <!-- TODO: fix for http://jira.codehaus.org/browse/MSITE-286? -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-site-plugin</artifactId>
+ <version>3.0</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.6</version>
+ <configuration>
+ <useManifestOnlyJar>false</useManifestOnlyJar>
+ <systemPropertyVariables>
+ <log4j.configuration>file:${project.basedir}/src/test/resources/log4j.xml</log4j.configuration>
+ <xn.billing.zuora.useSluggedRatePlans>false</xn.billing.zuora.useSluggedRatePlans>
+ </systemPropertyVariables>
+ <groups>fast,slow</groups>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <version>2.1.1</version>
+ <configuration>
+ <attachClasses>true</attachClasses>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty-maven-plugin</artifactId>
+ <version>7.5.1.v20110908</version>
+ <dependencies>
+ <dependency><!-- For LogLevelCounterAppender -->
+ <groupId>com.ning.jetty</groupId>
+ <artifactId>ning-service-skeleton-log4j</artifactId>
+ <version>${skeleton.version}</version>
+ <classifier>selfcontained</classifier>
+ <scope>runtime</scope>
+ </dependency>
+ <!-- Needed to redirect Jetty logs to slf4j -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.6.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.6.3</version>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <scanIntervalSeconds>60</scanIntervalSeconds>
+ <systemProperties>
+ <systemProperty>
+ <name>log4j.configuration</name>
+ <value>file:${basedir}/src/test/resources/log4j.xml</value>
+ </systemProperty>
+ </systemProperties>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/server/src/main/java/com/ning/billing/server/config/KillbillServerConfig.java b/server/src/main/java/com/ning/billing/server/config/KillbillServerConfig.java
new file mode 100644
index 0000000..fc29d5f
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/config/KillbillServerConfig.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010-2011 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.server.config;
+
+import org.skife.config.Config;
+import org.skife.config.Default;
+
+public interface KillbillServerConfig {
+
+}
diff --git a/server/src/main/java/com/ning/billing/server/healthchecks/KillbillHealthcheck.java b/server/src/main/java/com/ning/billing/server/healthchecks/KillbillHealthcheck.java
new file mode 100644
index 0000000..2cad006
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/healthchecks/KillbillHealthcheck.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2010-2011 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.server.healthchecks;
+
+import org.weakref.jmx.Managed;
+
+import com.yammer.metrics.core.HealthCheck;
+
+public class KillbillHealthcheck extends HealthCheck {
+
+ @Override
+ public String name() {
+ return "KillbillHealthCheck";
+ }
+
+ @Override
+ public Result check() {
+ try {
+ // STEPH obviously needs more than that
+ return Result.healthy();
+ } catch (Exception e) {
+ return Result.unhealthy(e);
+ }
+ }
+
+
+ @Managed
+ public boolean isHealthy() {
+ return check().isHealthy();
+ }
+}
diff --git a/server/src/main/java/com/ning/billing/server/listeners/GuiceModuleFactory.java b/server/src/main/java/com/ning/billing/server/listeners/GuiceModuleFactory.java
new file mode 100644
index 0000000..4ebd481
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/listeners/GuiceModuleFactory.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2010-2011 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.server.listeners;
+
+import com.google.inject.Module;
+
+public interface GuiceModuleFactory {
+ Module createModule();
+}
diff --git a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
new file mode 100644
index 0000000..880fc4f
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2010-2011 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.server.listeners;
+
+
+import javax.servlet.ServletContextEvent;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Injector;
+import com.ning.jetty.core.listeners.SetupServer;
+
+public class KillbillGuiceListener extends SetupServer {
+
+
+ private static Injector injectorInstance;
+
+ public static final Logger logger = LoggerFactory.getLogger(KillbillGuiceListener.class);
+
+
+ @Override
+ public void contextInitialized(final ServletContextEvent event) {
+
+ logger.info("GuiceListener : contextInitialized");
+
+ final String moduleFactoryClassName = event.getServletContext().getInitParameter("guiceModuleFactoryClass");
+
+ if (StringUtils.isEmpty(moduleFactoryClassName)) {
+ throw new IllegalStateException("Missing parameter 'guiceModuleFactoryClass' for IrsGuiceListener!");
+ }
+ try {
+ final Class<?> moduleFactoryClass = Class.forName(moduleFactoryClassName);
+ if (!GuiceModuleFactory.class.isAssignableFrom(moduleFactoryClass)) {
+ throw new IllegalStateException(String.format("%s exists but is not a guice module factory!", moduleFactoryClassName));
+ }
+
+ GuiceModuleFactory factory = GuiceModuleFactory.class.cast(moduleFactoryClass.newInstance());
+ logger.info("Instantiated " + moduleFactoryClassName + " as the factory for the main guice module.");
+
+ guiceModule = factory.createModule();
+ }
+ catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+
+ super.contextInitialized(event);
+
+ injectorInstance = this.injector(event);
+
+ }
+
+ public static Injector getInjectorInstance() {
+ return injectorInstance;
+ }
+}
diff --git a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceModuleFactory.java b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceModuleFactory.java
new file mode 100644
index 0000000..effa7bd
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceModuleFactory.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2010-2011 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.server.listeners;
+
+import static com.sun.jersey.api.core.PackagesResourceConfig.PROPERTY_PACKAGES;
+import static com.sun.jersey.api.core.ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS;
+import static com.sun.jersey.api.core.ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS;
+
+import java.lang.reflect.ParameterizedType;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Module;
+
+import com.ning.billing.server.healthchecks.KillbillHealthcheck;
+import com.ning.billing.server.modules.KillbillServerModule;
+import com.ning.jetty.base.modules.ServerModuleBuilder;
+import com.sun.jersey.api.container.filter.GZIPContentEncodingFilter;
+import com.sun.jersey.api.container.filter.LoggingFilter;
+import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
+
+
+public class KillbillGuiceModuleFactory implements GuiceModuleFactory {
+
+
+ private static final List<String> FILTERS = ImmutableList.of(GZIPContentEncodingFilter.class.getName(),
+ LoggingFilter.class.getName());
+ private static final List<String> RESOURCES = ImmutableList.of("com.ning.billing.jaxrs.resources");
+
+ private static final Map<String, String> JERSEY_PARAMS = ImmutableMap.of(
+ PROPERTY_CONTAINER_REQUEST_FILTERS, StringUtils.join(FILTERS, ";"),
+ // Though it would seem to make sense that filters should be applied to responses in reverse order, in fact the
+ // response filters appear to wrap each other up before executing, with the result being that execution order
+ // is the reverse of the declared order.
+ PROPERTY_CONTAINER_RESPONSE_FILTERS, StringUtils.join(FILTERS, ";"),
+ PROPERTY_PACKAGES, StringUtils.join(RESOURCES, ";")
+ );
+
+ private KillbillServerModule instantiateServiceModule() {
+ try {
+ /*
+ ParameterizedType parameterizedType = (ParameterizedType)getClass().getGenericSuperclass();
+ @SuppressWarnings("unchecked")
+ Class<KillbillServerModule> clazz = (Class<KillbillServerModule>)parameterizedType.getActualTypeArguments()[0];
+ */
+ return KillbillServerModule.class.newInstance();
+ }
+ catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public Module createModule() {
+ final ServerModuleBuilder builder = new ServerModuleBuilder();
+
+ builder.addHealthCheck(KillbillHealthcheck.class)
+ .addJMXExport(KillbillHealthcheck.class)
+ .addModule(instantiateServiceModule())
+ .enableLog4J()
+ .trackRequests()
+ .addFilter("/1.0/*", GuiceContainer.class, JERSEY_PARAMS);
+ return builder.build();
+ }
+
+}
diff --git a/server/src/main/java/com/ning/billing/server/listeners/KillbillLifecycleListener.java b/server/src/main/java/com/ning/billing/server/listeners/KillbillLifecycleListener.java
new file mode 100644
index 0000000..0aef190
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/listeners/KillbillLifecycleListener.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2010-2011 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.server.listeners;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Injector;
+import com.ning.billing.beatrix.lifecycle.DefaultLifecycle;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import com.ning.billing.util.bus.BusService;
+import com.ning.billing.util.bus.Bus.EventBusException;
+
+public class KillbillLifecycleListener implements ServletContextListener {
+
+
+ public static final Logger logger = LoggerFactory.getLogger(KillbillLifecycleListener.class);
+
+ private DefaultLifecycle killbillLifecycle;
+ private BusService killbillBusService;
+
+ private KillbillEventHandler killbilleventHandler;
+
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+
+ logger.info("KillbillLifecycleListener : contextInitialized");
+ Injector injector = KillbillGuiceListener.getInjectorInstance();
+ killbillLifecycle = injector.getInstance(DefaultLifecycle.class);
+ killbillBusService = injector.getInstance(BusService.class);
+
+ killbilleventHandler = new KillbillEventHandler();
+
+ //
+ // Fire all Startup levels up to service start
+ //
+ killbillLifecycle.fireStartupSequencePriorEventRegistration();
+ //
+ // Perform Bus registration
+ //
+ try {
+ killbillBusService.getBus().register(killbilleventHandler);
+ } catch (EventBusException e) {
+ logger.error("Failed to register for event notifications, this is bad exiting!", e);
+ System.exit(1);
+ }
+ // Let's start!
+ killbillLifecycle.fireStartupSequencePostEventRegistration();
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+ logger.info("IrsKillbillListener : contextDestroyed");
+ // Stop services
+ // Guice error, no need to fill the screen with useless stack traces
+ if (killbillLifecycle == null) {
+ return;
+ }
+
+ killbillLifecycle.fireShutdownSequencePriorEventUnRegistration();
+
+ try {
+ killbillBusService.getBus().unregister(killbilleventHandler);
+ } catch (EventBusException e) {
+ logger.warn("Failed to unregister for event notifications", e);
+ }
+
+ // Complete shutdown sequence
+ killbillLifecycle.fireShutdownSequencePostEventUnRegistration();
+ }
+
+
+ //
+ // At this point we have one generic handler in IRS that could dispatch notifications to the various pieces
+ // interested but we could the various pieces register their own handler directly
+ // //
+ public static class KillbillEventHandler {
+
+ /*
+ * IRS event handler for killbill entitlement events
+ */
+ @Subscribe
+ public void handleEntitlementevents(SubscriptionTransition event) {
+ logger.info("Killbill entitlement event {}", event.toString());
+ }
+ }
+}
diff --git a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
new file mode 100644
index 0000000..edf8f10
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2010-2011 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.server.modules;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.MBeanServer;
+
+import org.skife.config.ConfigurationObjectFactory;
+import org.skife.jdbi.v2.DBI;
+import org.skife.jdbi.v2.IDBI;
+
+import com.google.inject.AbstractModule;
+import com.ning.billing.account.glue.AccountModule;
+import com.ning.billing.analytics.setup.AnalyticsModule;
+import com.ning.billing.beatrix.glue.BeatrixModule;
+import com.ning.billing.catalog.glue.CatalogModule;
+import com.ning.billing.entitlement.glue.EntitlementModule;
+import com.ning.billing.invoice.glue.InvoiceModule;
+import com.ning.billing.jaxrs.resources.AccountResource;
+import com.ning.billing.jaxrs.resources.BundleResource;
+import com.ning.billing.jaxrs.resources.BundleTimelineResource;
+import com.ning.billing.jaxrs.resources.InvoiceResource;
+import com.ning.billing.jaxrs.resources.PaymentResource;
+import com.ning.billing.jaxrs.resources.SubscriptionResource;
+import com.ning.billing.payment.setup.PaymentModule;
+import com.ning.billing.server.config.KillbillServerConfig;
+import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.ClockModule;
+import com.ning.billing.util.glue.NotificationQueueModule;
+import com.ning.billing.util.glue.TagStoreModule;
+import com.ning.jetty.utils.providers.DBIProvider;
+
+public class KillbillServerModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ configureConfig();
+ configureDao();
+ configureResources();
+ installKillbillModules();
+ // STEPH Do we need that?
+ installMBeanExporter();
+ }
+
+ protected void configureDao() {
+ bind(IDBI.class).to(DBI.class).asEagerSingleton();
+ bind(DBI.class).toProvider(DBIProvider.class).asEagerSingleton();
+ }
+
+
+ protected void configureConfig() {
+ KillbillServerConfig config = new ConfigurationObjectFactory(System.getProperties()).build(KillbillServerConfig.class);
+ bind(KillbillServerConfig.class).toInstance(config);
+ }
+
+ protected void configureResources() {
+ bind(AccountResource.class).asEagerSingleton();
+ bind(BundleResource.class).asEagerSingleton();
+ bind(SubscriptionResource.class).asEagerSingleton();
+ bind(BundleTimelineResource.class).asEagerSingleton();
+ bind(InvoiceResource.class).asEagerSingleton();
+ bind(PaymentResource.class).asEagerSingleton();
+ }
+
+ protected void installKillbillModules() {
+ install(new BusModule());
+ install(new NotificationQueueModule());
+ install(new AccountModule());
+ install(new InvoiceModule());
+ install(new EntitlementModule());
+ install(new AnalyticsModule());
+ install(new PaymentModule());
+ install(new TagStoreModule());
+ install(new CatalogModule());
+ install(new BeatrixModule());
+ install(new ClockModule());
+ }
+
+ protected void installMBeanExporter() {
+ MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
+ bind(MBeanServer.class).toInstance(mbeanServer);
+ }
+}
diff --git a/server/src/main/jetty-config/contexts/root.xml b/server/src/main/jetty-config/contexts/root.xml
new file mode 100755
index 0000000..cdf71e1
--- /dev/null
+++ b/server/src/main/jetty-config/contexts/root.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Set name="contextPath">/</Set>
+ <Set name="war">
+ <SystemProperty name="xn.jetty.webapp.path" default="webapps/root"/>
+ </Set>
+ <Set name="defaultsDescriptor">
+ <SystemProperty name="xn.jetty.webapps.defaultsDescriptor" default="etc/webdefault.xml"/>
+ </Set>
+</Configure>
server/src/main/jetty-config/etc/webdefault.xml 186(+186 -0)
diff --git a/server/src/main/jetty-config/etc/webdefault.xml b/server/src/main/jetty-config/etc/webdefault.xml
new file mode 100755
index 0000000..19ae6ff
--- /dev/null
+++ b/server/src/main/jetty-config/etc/webdefault.xml
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app
+ xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ metadata-complete="true"
+ version="2.5">
+ <description>
+ Default web.xml file.
+ This file is applied to a Web application before it's own WEB_INF/web.xml file
+ </description>
+ <context-param>
+ <param-name>org.mortbay.jetty.webapp.NoTLDJarPattern</param-name>
+ <param-value>
+ start.jar|ant-.*\.jar|dojo-.*\.jar|jetty-.*\.jar|jsp-api-.*\.jar|junit-.*\.jar|servlet-api-.*\.jar|dnsns\.jar|rt\.jar|jsse\.jar|tools\.jar|sunpkcs11\.jar|sunjce_provider\.jar|xerces.*\.jar
+ </param-value>
+ </context-param>
+ <locale-encoding-mapping-list>
+ <locale-encoding-mapping>
+ <locale>ar</locale>
+ <encoding>ISO-8859-6</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>be</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>bg</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>ca</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>cs</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>da</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>de</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>el</locale>
+ <encoding>ISO-8859-7</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>en</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>es</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>et</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>fi</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>fr</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>hr</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>hu</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>is</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>it</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>iw</locale>
+ <encoding>ISO-8859-8</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>ja</locale>
+ <encoding>Shift_JIS</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>ko</locale>
+ <encoding>EUC-KR</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>lt</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>lv</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>mk</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>nl</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>no</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>pl</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>pt</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>ro</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>ru</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>sh</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>sk</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>sl</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>sq</locale>
+ <encoding>ISO-8859-2</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>sr</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>sv</locale>
+ <encoding>ISO-8859-1</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>tr</locale>
+ <encoding>ISO-8859-9</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>uk</locale>
+ <encoding>ISO-8859-5</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>zh</locale>
+ <encoding>GB2312</encoding>
+ </locale-encoding-mapping>
+ <locale-encoding-mapping>
+ <locale>zh_TW</locale>
+ <encoding>Big5</encoding>
+ </locale-encoding-mapping>
+ </locale-encoding-mapping-list>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Disable TRACE</web-resource-name>
+ <url-pattern>/</url-pattern>
+ <http-method>TRACE</http-method>
+ </web-resource-collection>
+ <auth-constraint/>
+ </security-constraint>
+</web-app>
+
server/src/main/jetty-config/ning-jetty-conf.xml 122(+122 -0)
diff --git a/server/src/main/jetty-config/ning-jetty-conf.xml b/server/src/main/jetty-config/ning-jetty-conf.xml
new file mode 100644
index 0000000..60764c5
--- /dev/null
+++ b/server/src/main/jetty-config/ning-jetty-conf.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+ <!-- =============================================================== -->
+ <!-- Setup MBean Server early -->
+ <!-- =============================================================== -->
+ <Call id="MBeanServer" class="java.lang.management.ManagementFactory" name="getPlatformMBeanServer"/>
+
+ <New id="MBeanContainer" class="org.eclipse.jetty.jmx.MBeanContainer">
+ <Arg>
+ <Ref id="MBeanServer"/>
+ </Arg>
+ </New>
+
+ <Get id="Container" name="container">
+ <Call name="addEventListener">
+ <Arg>
+ <Ref id="MBeanContainer"/>
+ </Arg>
+ </Call>
+ </Get>
+
+ <!-- =========================================================== -->
+ <!-- Server Thread Pool -->
+ <!-- =========================================================== -->
+ <Set name="ThreadPool">
+ <!-- Default queued blocking threadpool -->
+ <New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
+ <Set name="minThreads">
+ <SystemProperty name="xn.server.threads.min" default="10"/>
+ </Set>
+ <Set name="maxThreads">
+ <SystemProperty name="xn.server.threads.max" default="200"/>
+ </Set>
+ </New>
+ </Set>
+
+ <!-- =========================================================== -->
+ <!-- Set connectors -->
+ <!-- =========================================================== -->
+
+ <!-- Use this connector if NIO is not available. -->
+ <Call name="addConnector">
+ <Arg>
+ <New class="org.eclipse.jetty.server.bio.SocketConnector">
+ <Set name="host">
+ <SystemProperty name="xn.server.ip"/>
+ </Set>
+ <Set name="port">
+ <SystemProperty name="xn.server.port" default="8080"/>
+ </Set>
+ <Set name="maxIdleTime">300000</Set>
+ <Set name="Acceptors">2</Set>
+ <Set name="statsOn">true</Set>
+ <Set name="confidentialPort">
+ <SystemProperty name="xn.server.ssl.port" default="8443"/>
+ </Set>
+ </New>
+ </Arg>
+ </Call>
+
+ <Set name="handler">
+ <New class="org.eclipse.jetty.server.handler.StatisticsHandler">
+ <Set name="handler">
+ <New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
+ <Set name="handlers">
+ <Array type="org.eclipse.jetty.server.Handler">
+ <Item>
+ <New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
+ </Item>
+ <Item>
+ <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
+ </Item>
+ <Item>
+ <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/>
+ </Item>
+ </Array>
+ </Set>
+ </New>
+ </Set>
+ </New>
+ </Set>
+
+ <Ref id="RequestLog">
+ <Set name="requestLog">
+ <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
+ <Arg>
+ <SystemProperty name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log
+ </Arg>
+ <Set name="retainDays">30</Set>
+ <Set name="append">true</Set>
+ <Set name="extended">false</Set>
+ <Set name="LogTimeZone">GMT</Set>
+ </New>
+ </Set>
+ </Ref>
+
+ <Call name="addLifeCycle">
+ <Arg>
+ <New class="org.eclipse.jetty.deploy.ContextDeployer">
+ <Set name="contexts">
+ <Ref id="Contexts"/>
+ </Set>
+ <Set name="configurationDir">
+ <SystemProperty name="xn.jetty.contextDir" default="contexts"/>
+ </Set>
+ <Set name="scanInterval">1</Set>
+ </New>
+ </Arg>
+ </Call>
+
+ <!-- =========================================================== -->
+ <!-- extra options -->
+ <!-- =========================================================== -->
+ <Set name="stopAtShutdown">true</Set>
+ <Set name="sendServerVersion">false</Set>
+ <Set name="sendDateHeader">true</Set>
+ <Set name="gracefulShutdown">
+ <SystemProperty name="xn.jetty.gracefulShutdownTimeoutInMs" default="1000"/>
+ </Set>
+</Configure>
server/src/main/resources/catalog-demo.xml 641(+641 -0)
diff --git a/server/src/main/resources/catalog-demo.xml b/server/src/main/resources/catalog-demo.xml
new file mode 100644
index 0000000..8a97d57
--- /dev/null
+++ b/server/src/main/resources/catalog-demo.xml
@@ -0,0 +1,641 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+ ~ Copyright 2010-2011 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.
+ -->
+
+<!--
+Use cases covered so far:
+ Tiered Product (Pistol/Shotgun/Assault-Rifle)
+ Multiple changeEvent plan policies
+ Multiple PlanAlignment (see below, trial add-on alignments and rescue discount package)
+ Product transition rules
+ Add on (Scopes, Hoster)
+ Multi-pack addon (Extra-Ammo)
+ Addon Trial aligned to base plan (holster-monthly-regular)
+ Addon Trial aligned to creation (holster-monthly-special)
+ Rescue discount package (assault-rifle-annual-rescue)
+ Plan phase with a reccurring and a one off (refurbish-maintenance)
+ Phan with more than 2 phase (gunclub discount plans)
+
+Use Cases to do:
+ Tiered Add On
+ Riskfree period
+
+
+
+ -->
+<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
+
+ <effectiveDate>2011-01-01T00:00:00+00:00</effectiveDate>
+ <catalogName>Firearms</catalogName>
+
+ <currencies>
+ <currency>USD</currency>
+ <currency>EUR</currency>
+ <currency>GBP</currency>
+ </currencies>
+
+ <products>
+ <product name="Pistol">
+ <category>BASE</category>
+ </product>
+ <product name="Shotgun">
+ <category>BASE</category>
+ <available>
+ <addonProduct>Telescopic-Scope</addonProduct>
+ <addonProduct>Laser-Scope</addonProduct>
+ </available>
+ </product>
+ <product name="Assault-Rifle">
+ <category>BASE</category>
+ <included>
+ <addonProduct>Telescopic-Scope</addonProduct>
+ </included>
+ <available>
+ <addonProduct>Laser-Scope</addonProduct>
+ </available>
+ </product>
+ <product name="Telescopic-Scope">
+ <category>ADD_ON</category>
+ </product>
+ <product name="Laser-Scope">
+ <category>ADD_ON</category>
+ </product>
+ <product name="Holster">
+ <category>ADD_ON</category>
+ </product>
+ <product name="Extra-Ammo">
+ <category>ADD_ON</category>
+ </product>
+ <product name="Refurbish-Maintenance">
+ <category>ADD_ON</category>
+ </product>
+ </products>
+
+ <rules>
+ <changePolicy>
+ <changePolicyCase>
+ <phaseType>TRIAL</phaseType>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <toProduct>Assault-Rifle</toProduct>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <fromProduct>Pistol</fromProduct>
+ <toProduct>Shotgun</toProduct>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <toPriceList>rescue</toPriceList>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <fromBillingPeriod>MONTHLY</fromBillingPeriod>
+ <toBillingPeriod>ANNUAL</toBillingPeriod>
+ <policy>IMMEDIATE</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <fromBillingPeriod>ANNUAL</fromBillingPeriod>
+ <toBillingPeriod>MONTHLY</toBillingPeriod>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
+ <changePolicyCase>
+ <policy>END_OF_TERM</policy>
+ </changePolicyCase>
+ </changePolicy>
+ <changeAlignment>
+ <changeAlignmentCase>
+ <toPriceList>rescue</toPriceList>
+ <alignment>CHANGE_OF_PLAN</alignment>
+ </changeAlignmentCase>
+ <changeAlignmentCase>
+ <fromPriceList>rescue</fromPriceList>
+ <toPriceList>rescue</toPriceList>
+ <alignment>CHANGE_OF_PRICELIST</alignment>
+ </changeAlignmentCase>
+ <changeAlignmentCase>
+ <alignment>START_OF_SUBSCRIPTION</alignment>
+ </changeAlignmentCase>
+ </changeAlignment>
+ <cancelPolicy>
+ <cancelPolicyCase>
+ <phaseType>TRIAL</phaseType>
+ <policy>IMMEDIATE</policy>
+ </cancelPolicyCase>
+ <cancelPolicyCase>
+ <policy>END_OF_TERM</policy>
+ </cancelPolicyCase>
+ </cancelPolicy>
+ <createAlignment>
+ <createAlignmentCase>
+ <product>Laser-Scope</product>
+ <alignment>START_OF_SUBSCRIPTION</alignment>
+ </createAlignmentCase>
+ <createAlignmentCase>
+ <alignment>START_OF_BUNDLE</alignment>
+ </createAlignmentCase>
+ </createAlignment>
+ <billingAlignment>
+ <billingAlignmentCase>
+ <productCategory>ADD_ON</productCategory>
+ <alignment>BUNDLE</alignment>
+ </billingAlignmentCase>
+ <billingAlignmentCase>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <alignment>SUBSCRIPTION</alignment>
+ </billingAlignmentCase>
+ <billingAlignmentCase>
+ <alignment>ACCOUNT</alignment>
+ </billingAlignmentCase>
+ </billingAlignment>
+ <priceList>
+ <priceListCase>
+ <fromPriceList>rescue</fromPriceList>
+ <toPriceList>DEFAULT</toPriceList>
+ </priceListCase>
+ </priceList>
+ </rules>
+
+ <plans>
+ <plan name="pistol-monthly">
+ <product>Pistol</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice> <!-- empty price implies $0 -->
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>GBP</currency><value>29.95</value></price>
+ <price><currency>EUR</currency><value>29.95</value></price>
+ <price><currency>USD</currency><value>29.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="shotgun-monthly">
+ <product>Shotgun</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice></fixedPrice>
+ <!-- no price implies $0 -->
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ <number>-1</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>249.95</value></price>
+ <price><currency>EUR</currency><value>149.95</value></price>
+ <price><currency>GBP</currency><value>169.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="assault-rifle-monthly">
+ <product>Assault-Rifle</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>599.95</value></price>
+ <price><currency>EUR</currency><value>349.95</value></price>
+ <price><currency>GBP</currency><value>399.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="pistol-annual">
+ <product>Pistol</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>199.95</value></price>
+ <price><currency>EUR</currency><value>199.95</value></price>
+ <price><currency>GBP</currency><value>199.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="shotgun-annual">
+ <product>Shotgun</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>2399.95</value></price>
+ <price><currency>EUR</currency><value>1499.95</value></price>
+ <price><currency>GBP</currency><value>1699.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="assault-rifle-annual">
+ <product>Assault-Rifle</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>5999.95</value></price>
+ <price><currency>EUR</currency><value>3499.95</value></price>
+ <price><currency>GBP</currency><value>3999.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="pistol-annual-gunclub-discount">
+ <product>Pistol</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>6</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>9.95</value></price>
+ <price><currency>EUR</currency><value>9.95</value></price>
+ <price><currency>GBP</currency><value>9.95</value></price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>199.95</value></price>
+ <price><currency>EUR</currency><value>199.95</value></price>
+ <price><currency>GBP</currency><value>199.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="shotgun-annual-gunclub-discount">
+ <product>Shotgun</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>6</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>19.95</value></price>
+ <price><currency>EUR</currency><value>49.95</value></price>
+ <price><currency>GBP</currency><value>69.95</value></price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>2399.95</value></price>
+ <price><currency>EUR</currency><value>1499.95</value></price>
+ <price><currency>GBP</currency><value>1699.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="assault-rifle-annual-gunclub-discount">
+ <product>Assault-Rifle</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>6</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>99.95</value></price>
+ <price><currency>EUR</currency><value>99.95</value></price>
+ <price><currency>GBP</currency><value>99.95</value></price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>5999.95</value></price>
+ <price><currency>EUR</currency><value>3499.95</value></price>
+ <price><currency>GBP</currency><value>3999.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="laser-scope-monthly">
+ <product>Laser-Scope</product>
+ <initialPhases>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>1</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>999.95</value></price>
+ <price><currency>EUR</currency><value>499.95</value></price>
+ <price><currency>GBP</currency><value>999.95</value></price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>1999.95</value></price>
+ <price><currency>EUR</currency><value>1499.95</value></price>
+ <price><currency>GBP</currency><value>1999.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="telescopic-scope-monthly">
+ <product>Telescopic-Scope</product>
+ <initialPhases>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>1</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>399.95</value></price>
+ <price><currency>EUR</currency><value>299.95</value></price>
+ <price><currency>GBP</currency><value>399.95</value></price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>999.95</value></price>
+ <price><currency>EUR</currency><value>499.95</value></price>
+ <price><currency>GBP</currency><value>999.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="extra-ammo-monthly">
+ <product>Extra-Ammo</product>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>999.95</value></price>
+ <price><currency>EUR</currency><value>499.95</value></price>
+ <price><currency>GBP</currency><value>999.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ <plansAllowedInBundle>-1</plansAllowedInBundle> <!-- arbitrary number of these (multipack) -->
+ </plan>
+ <plan name="holster-monthly-regular">
+ <product>Holster</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>199.95</value></price>
+ <price><currency>EUR</currency><value>199.95</value></price>
+ <price><currency>GBP</currency><value>199.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="holster-monthly-special">
+ <product>Holster</product>
+ <initialPhases>
+ <phase type="TRIAL">
+ <duration>
+ <unit>DAYS</unit>
+ <number>30</number>
+ </duration>
+ <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+ <fixedPrice>
+ </fixedPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>199.95</value></price>
+ <price><currency>EUR</currency><value>199.95</value></price>
+ <price><currency>GBP</currency><value>199.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="assault-rifle-annual-rescue">
+ <product>Assault-Rifle</product>
+ <initialPhases>
+ <phase type="DISCOUNT">
+ <duration>
+ <unit>YEARS</unit>
+ <number>1</number>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>5999.95</value></price>
+ <price><currency>EUR</currency><value>3499.95</value></price>
+ <price><currency>GBP</currency><value>3999.95</value></price>
+ </recurringPrice>
+ </phase>
+ </initialPhases>
+ <finalPhase type="EVERGREEN">
+ <duration>
+ <unit>UNLIMITED</unit>
+ </duration>
+ <billingPeriod>ANNUAL</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>5999.95</value></price>
+ <price><currency>EUR</currency><value>3499.95</value></price>
+ <price><currency>GBP</currency><value>3999.95</value></price>
+ </recurringPrice>
+ </finalPhase>
+ </plan>
+ <plan name="refurbish-maintenance">
+ <product>Refurbish-Maintenance</product>
+ <finalPhase type="FIXEDTERM">
+ <duration>
+ <unit>MONTHS</unit>
+ <number>12</number>
+ </duration>
+ <billingPeriod>MONTHLY</billingPeriod>
+ <recurringPrice>
+ <price><currency>USD</currency><value>199.95</value></price>
+ <price><currency>EUR</currency><value>199.95</value></price>
+ <price><currency>GBP</currency><value>199.95</value></price>
+ </recurringPrice>
+ <fixedPrice>
+ <price><currency>USD</currency><value>599.95</value></price>
+ <price><currency>EUR</currency><value>599.95</value></price>
+ <price><currency>GBP</currency><value>599.95</value></price>
+ </fixedPrice>
+ </finalPhase>
+ </plan>
+ </plans>
+ <priceLists>
+ <defaultPriceList name="DEFAULT">
+ <plans>
+ <plan>pistol-monthly</plan>
+ <plan>shotgun-monthly</plan>
+ <plan>assault-rifle-monthly</plan>
+ <plan>pistol-annual</plan>
+ <plan>shotgun-annual</plan>
+ <plan>assault-rifle-annual</plan>
+ <plan>laser-scope-monthly</plan>
+ <plan>telescopic-scope-monthly</plan>
+ <plan>extra-ammo-monthly</plan>
+ <plan>holster-monthly-regular</plan>
+ <plan>refurbish-maintenance</plan>
+ </plans>
+ </defaultPriceList>
+ <childPriceList name="gunclubDiscount">
+ <plans>
+ <plan>pistol-monthly</plan>
+ <plan>shotgun-monthly</plan>
+ <plan>assault-rifle-monthly</plan>
+ <plan>pistol-annual-gunclub-discount</plan>
+ <plan>shotgun-annual-gunclub-discount</plan>
+ <plan>assault-rifle-annual-gunclub-discount</plan>
+ <plan>holster-monthly-special</plan>
+ </plans>
+ </childPriceList>
+ <childPriceList name="rescue">
+ <plans>
+ <plan>assault-rifle-annual-rescue</plan>
+ </plans>
+ </childPriceList>
+ </priceLists>
+
+</catalog>
diff --git a/server/src/main/resources/killbill-server.properties b/server/src/main/resources/killbill-server.properties
new file mode 100644
index 0000000..facf47d
--- /dev/null
+++ b/server/src/main/resources/killbill-server.properties
@@ -0,0 +1,11 @@
+com.ning.core.dao.url=jdbc:mysql://127.0.0.1:3306/killbill
+com.ning.core.dao.user=root
+com.ning.core.dao.password=root
+
+killbill.catalog.uri=file:src/main/resources/catalog-demo.xml
+
+killbill.entitlement.dao.claim.time=60000
+killbill.entitlement.dao.ready.max=1
+killbill.entitlement.engine.notifications.sleep=500
+user.timezone=UTC
+
server/src/main/resources/log4j.xml 63(+63 -0)
diff --git a/server/src/main/resources/log4j.xml b/server/src/main/resources/log4j.xml
new file mode 100644
index 0000000..cd2f7c0
--- /dev/null
+++ b/server/src/main/resources/log4j.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+ <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%p %d{ISO8601} %X{trace} %t %c %m%n"/>
+ </layout>
+ </appender>
+
+ <appender name="requests" class="org.apache.log4j.RollingFileAppender">
+ <param name="File" value="logs/http.log"/>
+ <param name="MaxFileSize" value="100MB"/>
+ <param name="MaxBackupIndex" value="1"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%p %d{ISO8601} %X{trace} %t %c %m%n"/>
+ </layout>
+ </appender>
+
+ <!-- Bilr response logs -->
+ <appender name="bilr_responses" class="org.apache.log4j.RollingFileAppender">
+ <param name="File" value="logs/bilr.log"/>
+ <param name="MaxFileSize" value="100MB"/>
+ <param name="MaxBackupIndex" value="10"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%p %d{ISO8601} %X{trace} %t %c %m%n"/>
+ </layout>
+ </appender>
+
+ <appender name="LOG_LEVEL_COUNTER" class="com.ning.jetty.log4j.LogLevelCounterAppender"/>
+
+ <logger name="com.sun.jersey.api.container.filter" additivity="false">
+ <level value="info"/>
+ <appender-ref ref="requests"/>
+ </logger>
+
+ <logger name="com.ning.metrics" additivity="false">
+ <level value="error"/>
+ <appender-ref ref="stdout"/>
+ </logger>
+
+ <!-- Silence com.ning.http.client.generators.InputStreamBodyGenerator inputStream.markSupported() not supported. Some features will not works
+ which doesn't seem to impact us -->
+ <logger name="com.ning.http.client.generators.InputStreamBodyGenerator">
+ <level value="error"/>
+ </logger>
+
+ <!-- Silence com.ning.http.client.providers.netty.NettyAsyncHttpProvider Number of application's worked threads is 8
+ which is not that useful -->
+ <logger name="com.ning.http.client.providers.netty.NettyAsyncHttpProvider">
+ <level value="warn"/>
+ </logger>
+
+ <logger name="com.ning">
+ <level value="info"/>
+ </logger>
+
+ <root>
+ <priority value="info"/>
+ <appender-ref ref="stdout"/>
+ <appender-ref ref="LOG_LEVEL_COUNTER"/>
+ </root>
+</log4j:configuration>
server/src/main/webapp/WEB-INF/web.xml 43(+43 -0)
diff --git a/server/src/main/webapp/WEB-INF/web.xml b/server/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..e9c0ee0
--- /dev/null
+++ b/server/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ version="2.5">
+ <display-name>irs</display-name>
+ <filter>
+ <!-- Guice emulates Servlet API with DI -->
+ <filter-name>guiceFilter</filter-name>
+ <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
+ </filter>
+ <filter-mapping>
+ <filter-name>guiceFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+ <listener>
+ <!-- Jersey insists on using java.util.logging (JUL) -->
+ <listener-class>com.ning.jetty.core.listeners.SetupJULBridge</listener-class>
+ </listener>
+ <!-- This param tells the IrsGuiceListener listener which factory to use for the root guice module -->
+ <context-param>
+ <param-name>guiceModuleFactoryClass</param-name>
+ <param-value>com.ning.billing.server.listeners.KillbillGuiceModuleFactory</param-value>
+ </context-param>
+ <listener>
+ <!-- Context listener: called at startup time and creates the injector -->
+ <listener-class>com.ning.billing.server.listeners.KillbillGuiceListener</listener-class>
+ </listener>
+ <listener>
+ <listener-class>com.ning.billing.server.listeners.KillbillLifecycleListener</listener-class>
+ </listener>
+ <!-- ServletHandler#handle requires a backend servlet, it won't be used though (handled by Guice) -->
+ <servlet>
+ <servlet-name>log-invalid-resources</servlet-name>
+ <servlet-class>com.ning.jetty.core.servlets.LogInvalidResourcesServlet</servlet-class>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>log-invalid-resources</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+</web-app>
server/src/test/resources/log4j.xml 36(+36 -0)
diff --git a/server/src/test/resources/log4j.xml b/server/src/test/resources/log4j.xml
new file mode 100644
index 0000000..1a946d3
--- /dev/null
+++ b/server/src/test/resources/log4j.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2010-2011 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.
+ -->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+ <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%p %d{ISO8601} %X{trace} %t %c %m%n"/>
+ </layout>
+ </appender>
+
+
+ <logger name="com.ning.billing.server">
+ <level value="info"/>
+ </logger>
+
+ <root>
+ <priority value="info"/>
+ <appender-ref ref="stdout"/>
+ </root>
+</log4j:configuration>
diff --git a/util/src/main/java/com/ning/billing/util/clock/Clock.java b/util/src/main/java/com/ning/billing/util/clock/Clock.java
index b41a36d..6b65aac 100644
--- a/util/src/main/java/com/ning/billing/util/clock/Clock.java
+++ b/util/src/main/java/com/ning/billing/util/clock/Clock.java
@@ -25,6 +25,5 @@ public interface Clock {
public DateTime getUTCNow();
-
//public DateTime addDuration(DateTime input, IDuration duration);
}
diff --git a/util/src/main/java/com/ning/billing/util/clock/DefaultClock.java b/util/src/main/java/com/ning/billing/util/clock/DefaultClock.java
index 8280a15..057a58c 100644
--- a/util/src/main/java/com/ning/billing/util/clock/DefaultClock.java
+++ b/util/src/main/java/com/ning/billing/util/clock/DefaultClock.java
@@ -36,6 +36,13 @@ public class DefaultClock implements Clock {
return getNow(DateTimeZone.UTC);
}
+ public static DateTime toUTCDateTime(DateTime input) {
+ if (input == null) {
+ return null;
+ }
+ DateTime result = input.toDateTime(DateTimeZone.UTC);
+ return truncateMs(result);
+ }
public static DateTime truncateMs(DateTime input) {
return input.minus(input.getMillisOfSecond());