killbill-memoizeit

Implement new endpoints to upload per tenant invoice resources

12/22/2014 9:54:56 PM

Details

diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
index 2a1948a..f0bf6c9 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
@@ -18,14 +18,18 @@
 
 package org.killbill.billing.jaxrs.resources;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
+import java.util.PropertyResourceBundle;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicReference;
@@ -81,6 +85,10 @@ import org.killbill.billing.payment.api.Payment;
 import org.killbill.billing.payment.api.PaymentApi;
 import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.PluginProperty;
+import org.killbill.billing.tenant.api.TenantApiException;
+import org.killbill.billing.tenant.api.TenantKV.TenantKey;
+import org.killbill.billing.tenant.api.TenantUserApi;
+import org.killbill.billing.util.LocaleUtils;
 import org.killbill.billing.util.api.AuditUserApi;
 import org.killbill.billing.util.api.CustomFieldApiException;
 import org.killbill.billing.util.api.CustomFieldUserApi;
@@ -110,6 +118,7 @@ import com.wordnik.swagger.annotations.ApiResponses;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 import static javax.ws.rs.core.MediaType.TEXT_HTML;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
 
 @Path(JaxrsResource.INVOICES_PATH)
 @Api(value = JaxrsResource.INVOICES_PATH, description = "Operations on invoices")
@@ -117,9 +126,12 @@ public class InvoiceResource extends JaxRsResourceBase {
 
     private static final Logger log = LoggerFactory.getLogger(InvoiceResource.class);
     private static final String ID_PARAM_NAME = "invoiceId";
+    private static final String LOCALE_PARAM_NAME = "locale";
 
     private final InvoiceUserApi invoiceApi;
     private final InvoiceNotifier invoiceNotifier;
+    private final TenantUserApi tenantApi;
+    private final Locale defaultLocale;
 
     @Inject
     public InvoiceResource(final AccountUserApi accountUserApi,
@@ -131,10 +143,13 @@ public class InvoiceResource extends JaxRsResourceBase {
                            final TagUserApi tagUserApi,
                            final CustomFieldUserApi customFieldUserApi,
                            final AuditUserApi auditUserApi,
+                           final TenantUserApi tenantApi,
                            final Context context) {
         super(uriBuilder, tagUserApi, customFieldUserApi, auditUserApi, accountUserApi, paymentApi, clock, context);
         this.invoiceApi = invoiceApi;
         this.invoiceNotifier = invoiceNotifier;
+        this.tenantApi = tenantApi;
+        this.defaultLocale = Locale.getDefault();
     }
 
     @Timed
@@ -318,7 +333,7 @@ public class InvoiceResource extends JaxRsResourceBase {
                 verifyNonNullOrEmpty(dryRunSubscriptionSpec.getProductName(), "DryRun subscription product category should be specified");
                 verifyNonNullOrEmpty(dryRunSubscriptionSpec.getBillingPeriod(), "DryRun subscription billingPeriod should be specified");
                 verifyNonNullOrEmpty(dryRunSubscriptionSpec.getSubscriptionId(), "DryRun subscriptionID should be specified");
-            }  else if (SubscriptionEventType.STOP_BILLING.toString().equals(dryRunSubscriptionSpec.getDryRunAction())) {
+            } else if (SubscriptionEventType.STOP_BILLING.toString().equals(dryRunSubscriptionSpec.getDryRunAction())) {
                 verifyNonNullOrEmpty(dryRunSubscriptionSpec.getSubscriptionId(), "DryRun subscriptionID should be specified");
             }
         }
@@ -568,6 +583,207 @@ public class InvoiceResource extends JaxRsResourceBase {
 
     @Timed
     @GET
+    @Path("/" + INVOICE_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
+    @Produces(TEXT_PLAIN)
+    @ApiOperation(value = "Retrieves the invoice translation for the tenant", response = String.class, hidden = true)
+    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid locale supplied"),
+                           @ApiResponse(code = 404, message = "Translation not found")})
+    public Response getInvoiceTranslation(@PathParam("locale") final String localeStr,
+                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, TenantApiException {
+        return getTemplateResource(localeStr, TenantKey.INVOICE_TRANSLATION_, request);
+    }
+
+    @Timed
+    @POST
+    @Produces(TEXT_PLAIN)
+    @Consumes(TEXT_PLAIN)
+    @Path("/" + INVOICE_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
+    @ApiOperation(value = "Upload the invoice translation for the tenant")
+    @ApiResponses(value = {})
+    public Response uploadInvoiceTranslation(final String invoiceTranslation,
+                                             @PathParam("locale") final String localeStr,
+                                             @QueryParam(QUERY_DELETE_IF_EXISTS) @DefaultValue("false") final boolean deleteIfExists,
+                                             @HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                             @HeaderParam(HDR_REASON) final String reason,
+                                             @HeaderParam(HDR_COMMENT) final String comment,
+                                             @javax.ws.rs.core.Context final HttpServletRequest request,
+                                             @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
+        return uploadTemplateResource(invoiceTranslation,
+                                      localeStr,
+                                      deleteIfExists,
+                                      TenantKey.INVOICE_TRANSLATION_,
+                                      "getInvoiceTranslation",
+                                      createdBy,
+                                      reason,
+                                      comment,
+                                      request,
+                                      uriInfo);
+    }
+
+    @Timed
+    @GET
+    @Path("/" + INVOICE_CATALOG_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
+    @Produces(TEXT_PLAIN)
+    @ApiOperation(value = "Retrieves the catalog translation for the tenant", response = String.class, hidden = true)
+    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid locale supplied"),
+                           @ApiResponse(code = 404, message = "Template not found")})
+    public Response getCatalogTranslation(@PathParam("locale") final String localeStr,
+                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, TenantApiException {
+        return getTemplateResource(localeStr, TenantKey.CATALOG_TRANSLATION_, request);
+    }
+
+    @Timed
+    @POST
+    @Produces(TEXT_PLAIN)
+    @Consumes(TEXT_PLAIN)
+    @Path("/" + INVOICE_CATALOG_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
+    @ApiOperation(value = "Upload the catalog translation for the tenant")
+    @ApiResponses(value = {})
+    public Response uploadCatalogTranslation(final String catalogTranslation,
+                                             @PathParam("locale") final String localeStr,
+                                             @QueryParam(QUERY_DELETE_IF_EXISTS) @DefaultValue("false") final boolean deleteIfExists,
+                                             @HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                             @HeaderParam(HDR_REASON) final String reason,
+                                             @HeaderParam(HDR_COMMENT) final String comment,
+                                             @javax.ws.rs.core.Context final HttpServletRequest request,
+                                             @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
+
+        return uploadTemplateResource(catalogTranslation,
+                                      localeStr,
+                                      deleteIfExists,
+                                      TenantKey.CATALOG_TRANSLATION_,
+                                      "getCatalogTranslation",
+                                      createdBy,
+                                      reason,
+                                      comment,
+                                      request,
+                                      uriInfo);
+    }
+
+    @Timed
+    @GET
+    @Path("/" + INVOICE_TEMPLATE)
+    @Produces(TEXT_HTML)
+    @ApiOperation(value = "Retrieves the invoice template for the tenant", response = String.class, hidden = true)
+    @ApiResponses(value = {@ApiResponse(code = 404, message = "Template not found")})
+    public Response getInvoiceTemplate(@PathParam("locale") final String localeStr,
+                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, TenantApiException {
+        return getTemplateResource(null, TenantKey.INVOICE_TEMPLATE, request);
+    }
+
+    @Timed
+    @POST
+    @Produces(TEXT_HTML)
+    @Consumes(TEXT_HTML)
+    @Path("/" + INVOICE_TEMPLATE)
+    @ApiOperation(value = "Upload the invoice template for the tenant")
+    @ApiResponses(value = {})
+    public Response uploadInvoiceTemplate(final String catalogTranslation,
+                                          @QueryParam(QUERY_DELETE_IF_EXISTS) @DefaultValue("false") final boolean deleteIfExists,
+                                          @HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                          @HeaderParam(HDR_REASON) final String reason,
+                                          @HeaderParam(HDR_COMMENT) final String comment,
+                                          @javax.ws.rs.core.Context final HttpServletRequest request,
+                                          @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
+        return uploadTemplateResource(catalogTranslation,
+                                      null,
+                                      deleteIfExists,
+                                      TenantKey.INVOICE_TEMPLATE,
+                                      "getInvoiceTemplate",
+                                      createdBy,
+                                      reason,
+                                      comment,
+                                      request,
+                                      uriInfo);
+    }
+
+    @Timed
+    @GET
+    @Path("/" + INVOICE_MP_TEMPLATE)
+    @Produces(TEXT_HTML)
+    @ApiOperation(value = "Retrieves the manualPay invoice template for the tenant", response = String.class, hidden = true)
+    @ApiResponses(value = {@ApiResponse(code = 404, message = "Template not found")})
+    public Response getInvoiceMPTemplate(@PathParam("locale") final String localeStr,
+                                         @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, TenantApiException {
+        return getTemplateResource(null, TenantKey.INVOICE_MP_TEMPLATE, request);
+    }
+
+    @Timed
+    @POST
+    @Produces(TEXT_HTML)
+    @Consumes(TEXT_HTML)
+    @Path("/" + INVOICE_MP_TEMPLATE)
+    @ApiOperation(value = "Upload the manualPay invoice template for the tenant")
+    @ApiResponses(value = {})
+    public Response uploadInvoiceMPTemplate(final String catalogTranslation,
+                                            @QueryParam(QUERY_DELETE_IF_EXISTS) @DefaultValue("false") final boolean deleteIfExists,
+                                            @HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                            @HeaderParam(HDR_REASON) final String reason,
+                                            @HeaderParam(HDR_COMMENT) final String comment,
+                                            @javax.ws.rs.core.Context final HttpServletRequest request,
+                                            @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
+        return uploadTemplateResource(catalogTranslation,
+                                      null,
+                                      deleteIfExists,
+                                      TenantKey.INVOICE_MP_TEMPLATE,
+                                      "getInvoiceMPTemplate",
+                                      createdBy,
+                                      reason,
+                                      comment,
+                                      request,
+                                      uriInfo);
+    }
+
+    private Response uploadTemplateResource(final String templateResource,
+                                            @Nullable final String localeStr,
+                                            final boolean deleteIfExists,
+                                            final TenantKey tenantKey,
+                                            final String getMethodStr,
+                                            final String createdBy,
+                                            final String reason,
+                                            final String comment,
+                                            final HttpServletRequest request,
+                                            final UriInfo uriInfo) throws Exception {
+        final String tenantKeyStr;
+        if (localeStr != null) {
+            // Validation purpose:  Will throw bad stream
+            final InputStream stream = new ByteArrayInputStream(templateResource.getBytes());
+            new PropertyResourceBundle(stream);
+            final Locale locale = localeStr != null ? LocaleUtils.toLocale(localeStr) : defaultLocale;
+            tenantKeyStr = LocaleUtils.localeString(locale, tenantKey.toString());
+        } else {
+            tenantKeyStr = tenantKey.toString();
+        }
+
+        final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+
+        if (!tenantApi.getTenantValueForKey(tenantKeyStr, callContext).isEmpty()) {
+            if (deleteIfExists) {
+                tenantApi.deleteTenantKey(tenantKeyStr, callContext);
+            } else {
+                return Response.status(Status.BAD_REQUEST).build();
+            }
+        }
+        tenantApi.addTenantKeyValue(tenantKeyStr, templateResource, callContext);
+        return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, getMethodStr, localeStr);
+    }
+
+    private Response getTemplateResource(@Nullable final String localeStr,
+                                         final TenantKey tenantKey,
+                                         final HttpServletRequest request) throws InvoiceApiException, TenantApiException {
+        final TenantContext tenantContext = context.createContext(request);
+        final String tenantKeyStr = localeStr != null ?
+                                    LocaleUtils.localeString(LocaleUtils.toLocale(localeStr), tenantKey.toString()) :
+                                    tenantKey.toString();
+        final List<String> result = tenantApi.getTenantValueForKey(tenantKeyStr, tenantContext);
+        return result.isEmpty() ? Response.status(Status.NOT_FOUND).build() : Response.status(Status.OK).entity(result.get(0)).build();
+    }
+
+
+
+
+    @Timed
+    @GET
     @Path("/{invoiceId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Produces(APPLICATION_JSON)
     @ApiOperation(value = "Retrieve invoice custom fields", response = CustomFieldJson.class, responseContainer = "List")
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
index 836d8c5..0ff5408 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
@@ -51,7 +51,7 @@ public interface JaxrsResource {
     /*
      * Patterns
      */
-    public static String STRING_PATTERN = "[\\w-]+";
+    public static String STRING_PATTERN = "\\w+";
     public static String UUID_PATTERN = "\\w+-\\w+-\\w+-\\w+-\\w+";
     public static String NUMBER_PATTERN = "[0-9]+";
     public static String ANYTHING_PATTERN = ".*";
@@ -101,6 +101,8 @@ public interface JaxrsResource {
     public static final String QUERY_START_DATE = "startDate";
     public static final String QUERY_END_DATE = "endDate";
 
+    public static final String QUERY_DELETE_IF_EXISTS = "deleteIfExists";
+
     public static final String QUERY_BUNDLE_TRANSFER_ADDON = "transferAddOn";
     public static final String QUERY_BUNDLE_TRANSFER_CANCEL_IMM = "cancelImmediately";
 
@@ -206,4 +208,11 @@ public interface JaxrsResource {
     public static final String HOSTED = "hosted";
     public static final String FORM = "form";
     public static final String NOTIFICATION = "notification";
+
+
+    public static final String INVOICE_TEMPLATE = "template";
+    public static final String INVOICE_MP_TEMPLATE = "manualPayTemplate";
+    public static final String INVOICE_TRANSLATION = "translation";
+    public static final String INVOICE_CATALOG_TRANSLATION = "catalogTranslation";
+
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/OverdueResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/OverdueResource.java
index 3b675fe..18df218 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/OverdueResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/OverdueResource.java
@@ -102,11 +102,11 @@ public class OverdueResource extends JaxRsResourceBase {
     @ApiOperation(value = "Upload the full catalog as XML")
     @ApiResponses(value = {})
     public Response uploadOverdueConfigXml(final String overdueXML,
-                                     @HeaderParam(HDR_CREATED_BY) final String createdBy,
-                                     @HeaderParam(HDR_REASON) final String reason,
-                                     @HeaderParam(HDR_COMMENT) final String comment,
-                                     @javax.ws.rs.core.Context final HttpServletRequest request,
-                                     @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
+                                           @HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                           @HeaderParam(HDR_REASON) final String reason,
+                                           @HeaderParam(HDR_COMMENT) final String comment,
+                                           @javax.ws.rs.core.Context final HttpServletRequest request,
+                                           @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
         // Validation purpose:  Will throw if bad XML or catalog validation fails
         final InputStream stream = new ByteArrayInputStream(overdueXML.getBytes());
         XMLLoader.getObjectFromStream(new URI(JaxrsResource.OVERDUE_PATH), stream, DefaultOverdueConfig.class);
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java b/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java
index bc46459..6fed6c5 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java
@@ -27,6 +27,7 @@ import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.tenant.api.TenantKV.TenantKey;
 import org.killbill.billing.tenant.dao.TenantDao;
 import org.killbill.billing.tenant.glue.DefaultTenantModule;
+import org.killbill.billing.util.LocaleUtils;
 
 public class DefaultTenantInternalApi implements TenantInternalApi {
 
@@ -50,25 +51,25 @@ public class DefaultTenantInternalApi implements TenantInternalApi {
 
     @Override
     public String getInvoiceTemplate(final Locale locale, final InternalTenantContext tenantContext) {
-        final List<String> values = tenantDao.getTenantValueForKey(getKeyFromLocale(TenantKey.INVOICE_TEMPLATE_.toString(), locale), tenantContext);
+        final List<String> values = tenantDao.getTenantValueForKey(LocaleUtils.localeString(locale, TenantKey.INVOICE_TEMPLATE.toString()), tenantContext);
         return getUniqueValue(values, "invoice template", tenantContext);
     }
 
     @Override
     public String getManualPayInvoiceTemplate(final Locale locale, final InternalTenantContext tenantContext) {
-        final List<String> values = tenantDao.getTenantValueForKey(getKeyFromLocale(TenantKey.INVOICE_MP_TEMPLATE_.toString(), locale), tenantContext);
+        final List<String> values = tenantDao.getTenantValueForKey(LocaleUtils.localeString(locale, TenantKey.INVOICE_MP_TEMPLATE.toString()), tenantContext);
         return getUniqueValue(values, "manual pay invoice template", tenantContext);
     }
 
     @Override
     public String getInvoiceTranslation(final Locale locale, final InternalTenantContext tenantContext) {
-        final List<String> values = tenantDao.getTenantValueForKey(getKeyFromLocale(TenantKey.INVOICE_TRANSLATION_.toString(), locale), tenantContext);
+        final List<String> values = tenantDao.getTenantValueForKey(LocaleUtils.localeString(locale, TenantKey.INVOICE_TRANSLATION_.toString()), tenantContext);
         return getUniqueValue(values, "invoice translation", tenantContext);
     }
 
     @Override
     public String getCatalogTranslation(final Locale locale, final InternalTenantContext tenantContext) {
-        final List<String> values = tenantDao.getTenantValueForKey(getKeyFromLocale(TenantKey.CATALOG_TRANSLATION_.toString(), locale), tenantContext);
+        final List<String> values = tenantDao.getTenantValueForKey(LocaleUtils.localeString(locale, TenantKey.CATALOG_TRANSLATION_.toString()), tenantContext);
         return getUniqueValue(values, "catalog translation", tenantContext);
     }
 
@@ -82,12 +83,4 @@ public class DefaultTenantInternalApi implements TenantInternalApi {
         }
         return values.get(0);
     }
-
-    private String getKeyFromLocale(final String prefix, final Locale locale) {
-        final StringBuilder tmp = new StringBuilder(prefix);
-        tmp.append(locale.getLanguage())
-           .append("_")
-           .append(locale.getCountry());
-        return tmp.toString();
-    }
 }
diff --git a/util/src/main/java/org/killbill/billing/util/LocaleUtils.java b/util/src/main/java/org/killbill/billing/util/LocaleUtils.java
index 5428003..f7b628f 100644
--- a/util/src/main/java/org/killbill/billing/util/LocaleUtils.java
+++ b/util/src/main/java/org/killbill/billing/util/LocaleUtils.java
@@ -18,11 +18,28 @@ package org.killbill.billing.util;
 
 import java.util.Locale;
 
+import javax.annotation.Nullable;
+
 public class LocaleUtils {
 
     private LocaleUtils() {
     }
 
+    public static String localeString(final Locale locale, @Nullable String prefix) {
+        final StringBuilder tmp = new StringBuilder();
+        if (prefix != null) {
+            tmp.append(prefix);
+            if (!prefix.endsWith("_")) {
+                tmp.append("_");
+            }
+        }
+        tmp.append(locale.getLanguage())
+           .append("_")
+           .append(locale.getCountry());
+        return tmp.toString();
+
+    }
+
     // From commons-lang
     public static Locale toLocale(final String str) {
         if (str == null) {