killbill-aplcache
Changes
invoice/src/main/java/org/killbill/billing/invoice/template/bundles/DefaultResourceBundleFactory.java 120(+120 -0)
invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java 13(+10 -3)
invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatterFactory.java 8(+6 -2)
invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java 27(+20 -7)
invoice/src/main/java/org/killbill/billing/invoice/template/translator/DefaultInvoiceTranslator.java 90(+25 -65)
invoice/src/main/java/org/killbill/billing/invoice/template/translator/InvoiceStrings.java 63(+0 -63)
invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceFormatter.java 43(+9 -34)
invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceItemFormatter.java 2(+1 -1)
util/src/main/java/org/killbill/billing/util/template/translation/DefaultCatalogTranslator.java 17(+4 -13)
Details
diff --git a/api/src/main/java/org/killbill/billing/invoice/api/formatters/InvoiceFormatterFactory.java b/api/src/main/java/org/killbill/billing/invoice/api/formatters/InvoiceFormatterFactory.java
index 3a2cdff..7601ae7 100644
--- a/api/src/main/java/org/killbill/billing/invoice/api/formatters/InvoiceFormatterFactory.java
+++ b/api/src/main/java/org/killbill/billing/invoice/api/formatters/InvoiceFormatterFactory.java
@@ -18,10 +18,13 @@ package org.killbill.billing.invoice.api.formatters;
import java.util.Locale;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.currency.api.CurrencyConversionApi;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.util.template.translation.TranslatorConfig;
public interface InvoiceFormatterFactory {
- public InvoiceFormatter createInvoiceFormatter(TranslatorConfig config, Invoice invoice, Locale locale, CurrencyConversionApi currencyConversionApi);
+
+ public InvoiceFormatter createInvoiceFormatter(TranslatorConfig config, Invoice invoice, Locale locale, CurrencyConversionApi currencyConversionApi,
+ ResourceBundleFactory bundleFactory, InternalTenantContext context);
}
diff --git a/api/src/main/java/org/killbill/billing/invoice/api/formatters/ResourceBundleFactory.java b/api/src/main/java/org/killbill/billing/invoice/api/formatters/ResourceBundleFactory.java
new file mode 100644
index 0000000..2c6a86e
--- /dev/null
+++ b/api/src/main/java/org/killbill/billing/invoice/api/formatters/ResourceBundleFactory.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 The Billing Project, LLC
+ *
+ * The Billing Project 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 org.killbill.billing.invoice.api.formatters;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import org.killbill.billing.callcontext.InternalTenantContext;
+
+public interface ResourceBundleFactory {
+
+ public enum ResourceBundleType {
+ INVOICE_TRANSLATION,
+ CATALOG_TRANSLATION
+ }
+
+ public ResourceBundle createBundle(Locale locale, String bundlePath, ResourceBundleType type, InternalTenantContext tenantContext);
+}
diff --git a/api/src/main/java/org/killbill/billing/tenant/api/TenantInternalApi.java b/api/src/main/java/org/killbill/billing/tenant/api/TenantInternalApi.java
index c1ff94a..b5adc7c 100644
--- a/api/src/main/java/org/killbill/billing/tenant/api/TenantInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/tenant/api/TenantInternalApi.java
@@ -18,11 +18,21 @@
package org.killbill.billing.tenant.api;
import java.util.List;
+import java.util.Locale;
import org.killbill.billing.callcontext.InternalTenantContext;
public interface TenantInternalApi {
+
public List<String> getTenantCatalogs(InternalTenantContext tenantContext);
public String getTenantOverdueConfig(InternalTenantContext tenantContext);
+
+ public String getInvoiceTemplate(Locale locale, InternalTenantContext tenantContext);
+
+ public String getManualPayInvoiceTemplate(Locale locale, InternalTenantContext tenantContext);
+
+ public String getInvoiceTranslation(Locale locale, InternalTenantContext tenantContext);
+
+ public String getCatalogTranslation(Locale locale, InternalTenantContext tenantContext);
}
diff --git a/api/src/main/java/org/killbill/billing/util/template/translation/Translator.java b/api/src/main/java/org/killbill/billing/util/template/translation/Translator.java
index 015cc26..70ce8a4 100644
--- a/api/src/main/java/org/killbill/billing/util/template/translation/Translator.java
+++ b/api/src/main/java/org/killbill/billing/util/template/translation/Translator.java
@@ -19,5 +19,5 @@ package org.killbill.billing.util.template.translation;
import java.util.Locale;
public interface Translator {
- public String getTranslation(Locale locale, String originalText);
+ public String getTranslation(String originalText);
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
index a8b7364..2118220 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
@@ -359,7 +359,7 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
}
}
- HtmlInvoice htmlInvoice = generator.generateInvoice(account, invoice, manualPay);
+ HtmlInvoice htmlInvoice = generator.generateInvoice(account, invoice, manualPay, internalContext);
return htmlInvoice.getBody();
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/glue/DefaultInvoiceModule.java b/invoice/src/main/java/org/killbill/billing/invoice/glue/DefaultInvoiceModule.java
index 268c9dc..1b56ec7 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/glue/DefaultInvoiceModule.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/glue/DefaultInvoiceModule.java
@@ -44,6 +44,8 @@ import org.killbill.billing.invoice.notification.NextBillingDateNotifier;
import org.killbill.billing.invoice.notification.NextBillingDatePoster;
import org.killbill.billing.invoice.notification.NullInvoiceNotifier;
import org.killbill.billing.invoice.plugin.api.InvoicePluginApi;
+import org.killbill.billing.invoice.template.bundles.DefaultResourceBundleFactory;
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory;
import org.killbill.billing.osgi.api.OSGIServiceRegistration;
import org.killbill.billing.platform.api.KillbillConfigSource;
import org.killbill.billing.util.config.InvoiceConfig;
@@ -89,6 +91,10 @@ public class DefaultInvoiceModule extends KillBillModule implements InvoiceModul
bind(InvoiceService.class).to(DefaultInvoiceService.class).asEagerSingleton();
}
+ protected void installResourceBundleFactory() {
+ bind(ResourceBundleFactory.class).to(DefaultResourceBundleFactory.class).asEagerSingleton();
+ }
+
@Override
public void installInvoiceMigrationApi() {
bind(InvoiceMigrationApi.class).to(DefaultInvoiceMigrationApi.class).asEagerSingleton();
@@ -142,5 +148,6 @@ public class DefaultInvoiceModule extends KillBillModule implements InvoiceModul
installInvoiceInternalApi();
installInvoicePaymentApi();
installInvoiceMigrationApi();
+ installResourceBundleFactory();
}
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/notification/EmailInvoiceNotifier.java b/invoice/src/main/java/org/killbill/billing/invoice/notification/EmailInvoiceNotifier.java
index ae7f044..b96220b 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/notification/EmailInvoiceNotifier.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/notification/EmailInvoiceNotifier.java
@@ -88,7 +88,7 @@ public class EmailInvoiceNotifier implements InvoiceNotifier {
final HtmlInvoice htmlInvoice;
try {
- htmlInvoice = generator.generateInvoice(account, invoice, manualPay);
+ htmlInvoice = generator.generateInvoice(account, invoice, manualPay, internalTenantContext);
} catch (IOException e) {
throw new InvoiceApiException(e, ErrorCode.EMAIL_SENDING_FAILED);
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/template/bundles/DefaultResourceBundleFactory.java b/invoice/src/main/java/org/killbill/billing/invoice/template/bundles/DefaultResourceBundleFactory.java
new file mode 100644
index 0000000..3a6fc9f
--- /dev/null
+++ b/invoice/src/main/java/org/killbill/billing/invoice/template/bundles/DefaultResourceBundleFactory.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 The Billing Project, LLC
+ *
+ * The Billing Project 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 org.killbill.billing.invoice.template.bundles;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+
+import javax.inject.Inject;
+
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory;
+import org.killbill.billing.tenant.api.TenantInternalApi;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.xmlloader.UriAccessor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Charsets;
+
+public class DefaultResourceBundleFactory implements ResourceBundleFactory {
+
+ private static final Logger logger = LoggerFactory.getLogger(DefaultResourceBundleFactory.class);
+
+ private final TenantInternalApi tenantApi;
+
+ @Inject
+ public DefaultResourceBundleFactory(final TenantInternalApi tenantApi) {
+ this.tenantApi = tenantApi;
+ }
+
+ @Override
+ public ResourceBundle createBundle(final Locale locale, final String bundlePath, final ResourceBundleType type, final InternalTenantContext tenantContext) {
+ if (tenantContext.getTenantRecordId() == InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID) {
+ return getGlobalBundle(locale, bundlePath);
+ }
+ final String bundle = getTenantBundleForType(locale, type, tenantContext);
+ if (bundle != null) {
+ try {
+ return new PropertyResourceBundle(new ByteArrayInputStream(bundle.getBytes(Charsets.UTF_8)));
+ } catch (IOException e) {
+ logger.warn("Failed to de-serialize the property bundle for tenant {} and locale {}", tenantContext.getTenantRecordId(), locale);
+ // Fall through...
+ }
+ }
+ return getGlobalBundle(locale, bundlePath);
+ }
+
+ private String getTenantBundleForType(final Locale locale, final ResourceBundleType type, final InternalTenantContext tenantContext) {
+ switch (type) {
+ case CATALOG_TRANSLATION:
+ return tenantApi.getCatalogTranslation(locale, tenantContext);
+
+ case INVOICE_TRANSLATION:
+ return tenantApi.getInvoiceTranslation(locale, tenantContext);
+
+ default:
+ logger.warn("Unexpected bundle type {} ", type);
+ return null;
+ }
+ }
+
+ private ResourceBundle getGlobalBundle(final Locale locale, final String bundlePath) {
+ try {
+ // Try to load the bundle from the classpath first
+ return ResourceBundle.getBundle(bundlePath, locale);
+ } catch (MissingResourceException ignored) {
+ }
+ // Try to load it from a properties file
+ final String propertiesFileNameWithCountry = bundlePath + "_" + locale.getLanguage() + "_" + locale.getCountry() + ".properties";
+ ResourceBundle bundle = getBundleFromPropertiesFile(propertiesFileNameWithCountry);
+ if (bundle != null) {
+ return bundle;
+ } else {
+ final String propertiesFileName = bundlePath + "_" + locale.getLanguage() + ".properties";
+ bundle = getBundleFromPropertiesFile(propertiesFileName);
+ }
+
+ return bundle;
+ }
+
+ private ResourceBundle getBundleFromPropertiesFile(final String propertiesFileName) {
+ try {
+ final InputStream inputStream = UriAccessor.accessUri(propertiesFileName);
+ if (inputStream == null) {
+ return null;
+ } else {
+ return new PropertyResourceBundle(inputStream);
+ }
+ } catch (IllegalArgumentException iae) {
+ return null;
+ } catch (MissingResourceException mrex) {
+ return null;
+ } catch (URISyntaxException e) {
+ return null;
+ } catch (IOException e) {
+ return null;
+ }
+ }
+}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
index b741c56..8ae278a 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
@@ -29,6 +29,9 @@ import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory;
+import org.killbill.billing.tenant.api.TenantInternalApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -65,13 +68,17 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
private final DateTimeFormatter dateFormatter;
private final Locale locale;
private final CurrencyConversionApi currencyConversionApi;
+ private final InternalTenantContext context;
+ private final ResourceBundleFactory bundleFactory;
- public DefaultInvoiceFormatter(final TranslatorConfig config, final Invoice invoice, final Locale locale, final CurrencyConversionApi currencyConversionApi) {
+ public DefaultInvoiceFormatter(final TranslatorConfig config, final Invoice invoice, final Locale locale, final CurrencyConversionApi currencyConversionApi, final ResourceBundleFactory bundleFactory, final InternalTenantContext context) {
this.config = config;
this.invoice = invoice;
- dateFormatter = DateTimeFormat.mediumDate().withLocale(locale);
+ this.dateFormatter = DateTimeFormat.mediumDate().withLocale(locale);
this.locale = locale;
this.currencyConversionApi = currencyConversionApi;
+ this.bundleFactory = bundleFactory;
+ this.context = context;
}
@Override
@@ -109,7 +116,7 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
final List<InvoiceItem> formatters = new ArrayList<InvoiceItem>();
for (final InvoiceItem item : invoiceItems) {
- formatters.add(new DefaultInvoiceItemFormatter(config, item, dateFormatter, locale));
+ formatters.add(new DefaultInvoiceItemFormatter(config, item, dateFormatter, locale, context, bundleFactory));
}
return formatters;
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatterFactory.java b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatterFactory.java
index b1212aa..890fb30 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatterFactory.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatterFactory.java
@@ -18,16 +18,20 @@ package org.killbill.billing.invoice.template.formatters;
import java.util.Locale;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.currency.api.CurrencyConversionApi;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.formatters.InvoiceFormatter;
import org.killbill.billing.invoice.api.formatters.InvoiceFormatterFactory;
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory;
+import org.killbill.billing.tenant.api.TenantInternalApi;
import org.killbill.billing.util.template.translation.TranslatorConfig;
public class DefaultInvoiceFormatterFactory implements InvoiceFormatterFactory {
@Override
- public InvoiceFormatter createInvoiceFormatter(final TranslatorConfig config, final Invoice invoice, final Locale locale, CurrencyConversionApi currencyConversionApi) {
- return new DefaultInvoiceFormatter(config, invoice, locale, currencyConversionApi);
+ public InvoiceFormatter createInvoiceFormatter(final TranslatorConfig config, final Invoice invoice, final Locale locale, CurrencyConversionApi currencyConversionApi,
+ final ResourceBundleFactory bundleFactory, final InternalTenantContext context) {
+ return new DefaultInvoiceFormatter(config, invoice, locale, currencyConversionApi, bundleFactory, context);
}
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
index ef0cca6..51ddcc6 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
@@ -19,19 +19,25 @@ package org.killbill.billing.invoice.template.formatters;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.Locale;
+import java.util.ResourceBundle;
import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormatter;
-
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.invoice.api.InvoiceItem;
import org.killbill.billing.invoice.api.InvoiceItemType;
import org.killbill.billing.invoice.api.formatters.InvoiceItemFormatter;
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory;
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory.ResourceBundleType;
+import org.killbill.billing.util.LocaleUtils;
import org.killbill.billing.util.template.translation.DefaultCatalogTranslator;
import org.killbill.billing.util.template.translation.Translator;
import org.killbill.billing.util.template.translation.TranslatorConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
@@ -49,12 +55,18 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
private final DateTimeFormatter dateFormatter;
private final Locale locale;
- public DefaultInvoiceItemFormatter(final TranslatorConfig config, final InvoiceItem item, final DateTimeFormatter dateFormatter, final Locale locale) {
+ public DefaultInvoiceItemFormatter(final TranslatorConfig config,
+ final InvoiceItem item,
+ final DateTimeFormatter dateFormatter,
+ final Locale locale,
+ final InternalTenantContext context,
+ final ResourceBundleFactory bundleFactory) {
this.item = item;
this.dateFormatter = dateFormatter;
this.locale = locale;
-
- this.translator = new DefaultCatalogTranslator(config);
+ final ResourceBundle bundle = bundleFactory.createBundle(locale, config.getCatalogBundlePath(), ResourceBundleType.CATALOG_TRANSLATION, context);
+ final ResourceBundle defaultBundle = bundleFactory.createBundle(LocaleUtils.toLocale(config.getDefaultLocale()), config.getCatalogBundlePath(), ResourceBundleType.CATALOG_TRANSLATION, context);
+ this.translator = new DefaultCatalogTranslator(bundle, defaultBundle);
}
@Override
@@ -126,17 +138,17 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
@Override
public String getPlanName() {
- return Strings.nullToEmpty(translator.getTranslation(locale, item.getPlanName()));
+ return Strings.nullToEmpty(translator.getTranslation(item.getPlanName()));
}
@Override
public String getPhaseName() {
- return Strings.nullToEmpty(translator.getTranslation(locale, item.getPhaseName()));
+ return Strings.nullToEmpty(translator.getTranslation(item.getPhaseName()));
}
@Override
public String getUsageName() {
- return Strings.nullToEmpty(translator.getTranslation(locale, item.getUsageName()));
+ return Strings.nullToEmpty(translator.getTranslation(item.getUsageName()));
}
@Override
@@ -168,4 +180,5 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
public boolean matches(final Object other) {
throw new UnsupportedOperationException();
}
+
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/template/HtmlInvoiceGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/template/HtmlInvoiceGenerator.java
index e04a8f1..3e0e0bc 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/template/HtmlInvoiceGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/template/HtmlInvoiceGenerator.java
@@ -17,21 +17,31 @@
package org.killbill.billing.invoice.template;
import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.ResourceBundle;
import javax.annotation.Nullable;
import org.killbill.billing.account.api.Account;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.currency.api.CurrencyConversionApi;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.formatters.InvoiceFormatter;
import org.killbill.billing.invoice.api.formatters.InvoiceFormatterFactory;
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory;
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory.ResourceBundleType;
import org.killbill.billing.invoice.template.translator.DefaultInvoiceTranslator;
+import org.killbill.billing.tenant.api.TenantInternalApi;
import org.killbill.billing.util.LocaleUtils;
+import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.email.templates.TemplateEngine;
+import org.killbill.billing.util.io.IOUtils;
import org.killbill.billing.util.template.translation.TranslatorConfig;
+import org.killbill.xmlloader.UriAccessor;
import com.google.common.base.Strings;
import com.google.inject.Inject;
@@ -39,46 +49,75 @@ import com.google.inject.Inject;
public class HtmlInvoiceGenerator {
private final InvoiceFormatterFactory factory;
- private final TemplateEngine templateEngine;
private final TranslatorConfig config;
private final CurrencyConversionApi currencyConversionApi;
+ private final TemplateEngine templateEngine;
+ private final TenantInternalApi tenantApi;
+ private final ResourceBundleFactory bundleFactory;
@Inject
- public HtmlInvoiceGenerator(final InvoiceFormatterFactory factory, final TemplateEngine templateEngine,
- final TranslatorConfig config, final CurrencyConversionApi currencyConversionApi) {
+ public HtmlInvoiceGenerator(final InvoiceFormatterFactory factory,
+ final TemplateEngine templateEngine,
+ final TranslatorConfig config,
+ final CurrencyConversionApi currencyConversionApi,
+ final ResourceBundleFactory bundleFactory,
+ final TenantInternalApi tenantInternalApi) {
this.factory = factory;
- this.templateEngine = templateEngine;
this.config = config;
this.currencyConversionApi = currencyConversionApi;
+ this.templateEngine = templateEngine;
+ this.bundleFactory = bundleFactory;
+ this.tenantApi = tenantInternalApi;
}
- public HtmlInvoice generateInvoice(final Account account, @Nullable final Invoice invoice, final boolean manualPay) throws IOException {
+ public HtmlInvoice generateInvoice(final Account account, @Nullable final Invoice invoice, final boolean manualPay, final InternalTenantContext context) throws IOException {
// Don't do anything if the invoice is null
if (invoice == null) {
return null;
}
- HtmlInvoice invoiceData = new HtmlInvoice();
- final Map<String, Object> data = new HashMap<String, Object>();
- final DefaultInvoiceTranslator invoiceTranslator = new DefaultInvoiceTranslator(config);
final String accountLocale = Strings.emptyToNull(account.getLocale());
- // If no Locale is defined, use the default JVM one
final Locale locale = accountLocale == null ? Locale.getDefault() : LocaleUtils.toLocale(accountLocale);
- invoiceTranslator.setLocale(locale);
+
+ final HtmlInvoice invoiceData = new HtmlInvoice();
+ final Map<String, Object> data = new HashMap<String, Object>();
+
+ final ResourceBundle invoiceBundle = accountLocale != null ?
+ bundleFactory.createBundle(LocaleUtils.toLocale(accountLocale), config.getInvoiceTemplateBundlePath(), ResourceBundleType.INVOICE_TRANSLATION, context) : null;
+ final ResourceBundle defaultInvoiceBundle = bundleFactory.createBundle(Locale.getDefault(), config.getInvoiceTemplateBundlePath(), ResourceBundleType.INVOICE_TRANSLATION, context);
+ final DefaultInvoiceTranslator invoiceTranslator = new DefaultInvoiceTranslator(invoiceBundle, defaultInvoiceBundle);
+
data.put("text", invoiceTranslator);
data.put("account", account);
- final InvoiceFormatter formattedInvoice = factory.createInvoiceFormatter(config, invoice, locale, currencyConversionApi);
+ final InvoiceFormatter formattedInvoice = factory.createInvoiceFormatter(config, invoice, locale, currencyConversionApi, bundleFactory, context);
data.put("invoice", formattedInvoice);
invoiceData.setSubject(invoiceTranslator.getInvoiceEmailSubject());
+ final String templateText = getTemplateText(locale, manualPay, context);
+ invoiceData.setBody(templateEngine.executeTemplateText(templateText, data));
+ return invoiceData;
+ }
+
+ private String getTemplateText(final Locale locale, final boolean manualPay, final InternalTenantContext context) throws IOException {
- if (manualPay) {
- invoiceData.setBody(templateEngine.executeTemplate(config.getManualPayTemplateName(), data));
- } else {
- invoiceData.setBody(templateEngine.executeTemplate(config.getTemplateName(), data));
+ if (context.getTenantRecordId() == InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID) {
+ return getDefaultTemplate(manualPay ? config.getManualPayTemplateName() : config.getTemplateName());
}
+ final String template = manualPay ?
+ tenantApi.getManualPayInvoiceTemplate(locale, context) :
+ tenantApi.getInvoiceTemplate(locale, context);
+ return template == null ?
+ getDefaultTemplate(manualPay ? config.getManualPayTemplateName() : config.getTemplateName()) :
+ template;
+ }
- return invoiceData;
+ private String getDefaultTemplate(final String templateName) throws IOException {
+ try {
+ final InputStream templateStream = UriAccessor.accessUri(templateName);
+ return IOUtils.toString(templateStream);
+ } catch (URISyntaxException e) {
+ throw new IOException(e);
+ }
}
}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/template/translator/DefaultInvoiceTranslator.java b/invoice/src/main/java/org/killbill/billing/invoice/template/translator/DefaultInvoiceTranslator.java
index 4bb5ef1..451665d 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/template/translator/DefaultInvoiceTranslator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/template/translator/DefaultInvoiceTranslator.java
@@ -16,139 +16,99 @@
package org.killbill.billing.invoice.template.translator;
-import java.util.Locale;
+import java.util.ResourceBundle;
import org.killbill.billing.util.template.translation.DefaultTranslatorBase;
import org.killbill.billing.util.template.translation.TranslatorConfig;
-import com.google.inject.Inject;
+public class DefaultInvoiceTranslator extends DefaultTranslatorBase {
-public class DefaultInvoiceTranslator extends DefaultTranslatorBase implements InvoiceStrings {
-
- private Locale locale;
-
- @Inject
- public DefaultInvoiceTranslator(final TranslatorConfig config) {
- super(config);
- }
-
- public void setLocale(final Locale locale) {
- this.locale = locale;
- }
-
- @Override
- protected String getBundlePath() {
- return config.getInvoiceTemplateBundlePath();
- }
-
- @Override
- protected String getTranslationType() {
- return "invoice";
+ public DefaultInvoiceTranslator(final ResourceBundle bundle, final ResourceBundle defaultBundle) {
+ super(bundle, defaultBundle);
}
- @Override
public String getInvoiceEmailSubject() {
- String subject = getTranslation(locale, "invoiceEmailSubject");
+ String subject = getTranslation("invoiceEmailSubject");
return (!"invoiceEmailSubject".equals(subject)) ? subject : null;
}
- @Override
public String getInvoiceTitle() {
- return getTranslation(locale, "invoiceTitle");
+ return getTranslation("invoiceTitle");
}
- @Override
public String getInvoiceDate() {
- return getTranslation(locale, "invoiceDate");
+ return getTranslation("invoiceDate");
}
- @Override
public String getInvoiceNumber() {
- return getTranslation(locale, "invoiceNumber");
+ return getTranslation("invoiceNumber");
}
- @Override
public String getAccountOwnerName() {
- return getTranslation(locale, "accountOwnerName");
+ return getTranslation("accountOwnerName");
}
- @Override
public String getAccountOwnerEmail() {
- return getTranslation(locale, "accountOwnerEmail");
+ return getTranslation("accountOwnerEmail");
}
- @Override
public String getAccountOwnerPhone() {
- return getTranslation(locale, "accountOwnerPhone");
+ return getTranslation("accountOwnerPhone");
}
- @Override
public String getCompanyName() {
- return getTranslation(locale, "companyName");
+ return getTranslation("companyName");
}
- @Override
public String getCompanyAddress() {
- return getTranslation(locale, "companyAddress");
+ return getTranslation("companyAddress");
}
- @Override
public String getCompanyCityProvincePostalCode() {
- return getTranslation(locale, "companyCityProvincePostalCode");
+ return getTranslation("companyCityProvincePostalCode");
}
- @Override
public String getCompanyCountry() {
- return getTranslation(locale, "companyCountry");
+ return getTranslation("companyCountry");
}
- @Override
public String getCompanyUrl() {
- return getTranslation(locale, "companyUrl");
+ return getTranslation("companyUrl");
}
- @Override
public String getInvoiceItemBundleName() {
- return getTranslation(locale, "invoiceItemBundleName");
+ return getTranslation("invoiceItemBundleName");
}
- @Override
public String getInvoiceItemDescription() {
- return getTranslation(locale, "invoiceItemDescription");
+ return getTranslation("invoiceItemDescription");
}
- @Override
public String getInvoiceItemServicePeriod() {
- return getTranslation(locale, "invoiceItemServicePeriod");
+ return getTranslation("invoiceItemServicePeriod");
}
- @Override
public String getInvoiceItemAmount() {
- return getTranslation(locale, "invoiceItemAmount");
+ return getTranslation("invoiceItemAmount");
}
- @Override
public String getInvoiceAmount() {
- return getTranslation(locale, "invoiceAmount");
+ return getTranslation("invoiceAmount");
}
- @Override
public String getInvoiceAmountPaid() {
- return getTranslation(locale, "invoiceAmountPaid");
+ return getTranslation("invoiceAmountPaid");
}
- @Override
public String getInvoiceBalance() {
- return getTranslation(locale, "invoiceBalance");
+ return getTranslation("invoiceBalance");
}
- @Override
public String getProcessedPaymentCurrency() {
- return getTranslation(locale, "processedPaymentCurrency");
+ return getTranslation("processedPaymentCurrency");
}
- @Override
public String getProcessedPaymentRate() {
- return getTranslation(locale, "processedPaymentRate");
+ return getTranslation("processedPaymentRate");
}
}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/InvoiceTestSuiteNoDB.java b/invoice/src/test/java/org/killbill/billing/invoice/InvoiceTestSuiteNoDB.java
index aa62f70..3db8940 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/InvoiceTestSuiteNoDB.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/InvoiceTestSuiteNoDB.java
@@ -25,6 +25,7 @@ import org.killbill.billing.invoice.api.InvoiceInternalApi;
import org.killbill.billing.invoice.api.InvoiceMigrationApi;
import org.killbill.billing.invoice.api.InvoicePaymentApi;
import org.killbill.billing.invoice.api.InvoiceUserApi;
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory;
import org.killbill.billing.invoice.dao.InvoiceDao;
import org.killbill.billing.invoice.generator.InvoiceGenerator;
import org.killbill.billing.invoice.glue.TestInvoiceModuleNoDB;
@@ -91,6 +92,8 @@ public abstract class InvoiceTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
protected CurrencyConversionApi currencyConversionApi;
@Inject
protected UsageUserApi usageUserApi;
+ @Inject
+ protected ResourceBundleFactory resourceBundleFactory;
@Override
protected KillbillConfigSource getConfigSource() {
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceFormatter.java b/invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceFormatter.java
index 6000893..5e18596 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceFormatter.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceFormatter.java
@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.ResourceBundle;
import java.util.UUID;
import org.joda.time.LocalDate;
@@ -34,6 +35,7 @@ import org.killbill.billing.invoice.api.InvoiceItemType;
import org.killbill.billing.invoice.api.InvoicePaymentType;
import org.killbill.billing.invoice.api.formatters.InvoiceFormatter;
import org.killbill.billing.invoice.api.formatters.InvoiceFormatterFactory;
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory.ResourceBundleType;
import org.killbill.billing.invoice.model.CreditAdjInvoiceItem;
import org.killbill.billing.invoice.model.CreditBalanceAdjInvoiceItem;
import org.killbill.billing.invoice.model.DefaultInvoice;
@@ -87,7 +89,7 @@ public class TestDefaultInvoiceFormatter extends InvoiceTestSuiteNoDB {
Assert.assertEquals(invoice.getCreditedAmount().doubleValue(), 0.00);
// Verify the merge
- final InvoiceFormatter formatter = new DefaultInvoiceFormatter(config, invoice, Locale.US, null);
+ final InvoiceFormatter formatter = new DefaultInvoiceFormatter(config, invoice, Locale.US, null, resourceBundleFactory, internalCallContext);
final List<InvoiceItem> invoiceItems = formatter.getInvoiceItems();
Assert.assertEquals(invoiceItems.size(), 1);
Assert.assertEquals(invoiceItems.get(0).getInvoiceItemType(), InvoiceItemType.FIXED);
@@ -141,7 +143,7 @@ public class TestDefaultInvoiceFormatter extends InvoiceTestSuiteNoDB {
Assert.assertEquals(invoice.getRefundedAmount().doubleValue(), -1.00);
// Verify the merge
- final InvoiceFormatter formatter = new DefaultInvoiceFormatter(config, invoice, Locale.US, null);
+ final InvoiceFormatter formatter = new DefaultInvoiceFormatter(config, invoice, Locale.US, null, resourceBundleFactory, internalCallContext);
final List<InvoiceItem> invoiceItems = formatter.getInvoiceItems();
Assert.assertEquals(invoiceItems.size(), 4);
Assert.assertEquals(invoiceItems.get(0).getInvoiceItemType(), InvoiceItemType.FIXED);
@@ -320,41 +322,14 @@ public class TestDefaultInvoiceFormatter extends InvoiceTestSuiteNoDB {
final Map<String, Object> data = new HashMap<String, Object>();
- final DefaultInvoiceTranslator translator = new DefaultInvoiceTranslator(new TranslatorConfig() {
- @Override
- public String getDefaultLocale() {
- return "en_US";
- }
+ final String bundlePath = "org/killbill/billing/util/template/translation/InvoiceTranslation";
+ final ResourceBundle bundle = resourceBundleFactory.createBundle(Locale.US, bundlePath, ResourceBundleType.INVOICE_TRANSLATION, internalCallContext);
- @Override
- public String getCatalogBundlePath() {
- return null;
- }
+ final DefaultInvoiceTranslator translator = new DefaultInvoiceTranslator(bundle, null);
- @Override
- public String getInvoiceTemplateBundlePath() {
- return "org/killbill/billing/util/template/translation/InvoiceTranslation";
- }
-
- @Override
- public String getTemplateName() {
- return null;
- }
-
- @Override
- public String getManualPayTemplateName() {
- return null;
- }
-
- @Override
- public Class<? extends InvoiceFormatterFactory> getInvoiceFormatterFactoryClass() {
- return null;
- }
- });
- translator.setLocale(Locale.US);
data.put("text", translator);
- data.put("invoice", new DefaultInvoiceFormatter(config, invoice, Locale.US, currencyConversionApi));
+ data.put("invoice", new DefaultInvoiceFormatter(config, invoice, Locale.US, currencyConversionApi, resourceBundleFactory, internalCallContext));
final String formattedText = templateEngine.executeTemplateText(template, data);
@@ -363,7 +338,7 @@ public class TestDefaultInvoiceFormatter extends InvoiceTestSuiteNoDB {
private void checkOutput(final Invoice invoice, final String template, final String expected, final Locale locale) {
final Map<String, Object> data = new HashMap<String, Object>();
- data.put("invoice", new DefaultInvoiceFormatter(config, invoice, locale, null));
+ data.put("invoice", new DefaultInvoiceFormatter(config, invoice, locale, null, resourceBundleFactory, internalCallContext));
final String formattedText = templateEngine.executeTemplateText(template, data);
Assert.assertEquals(formattedText, expected);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceItemFormatter.java b/invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceItemFormatter.java
index ca988e3..fbac29d 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceItemFormatter.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceItemFormatter.java
@@ -111,7 +111,7 @@ public class TestDefaultInvoiceItemFormatter extends InvoiceTestSuiteNoDB {
private void checkOutput(final InvoiceItem invoiceItem, final String template, final String expected, final Locale locale) {
final Map<String, Object> data = new HashMap<String, Object>();
- data.put("invoiceItem", new DefaultInvoiceItemFormatter(config, invoiceItem, DateTimeFormat.mediumDate().withLocale(locale), locale));
+ data.put("invoiceItem", new DefaultInvoiceItemFormatter(config, invoiceItem, DateTimeFormat.mediumDate().withLocale(locale), locale, internalCallContext, resourceBundleFactory));
final String formattedText = templateEngine.executeTemplateText(template, data);
Assert.assertEquals(formattedText, expected);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestHtmlInvoiceGenerator.java b/invoice/src/test/java/org/killbill/billing/invoice/TestHtmlInvoiceGenerator.java
index 53f096f..70b1cc1 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestHtmlInvoiceGenerator.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestHtmlInvoiceGenerator.java
@@ -54,12 +54,12 @@ public class TestHtmlInvoiceGenerator extends InvoiceTestSuiteNoDB {
final TranslatorConfig config = new ConfigurationObjectFactory(skifeConfigSource).build(TranslatorConfig.class);
final TemplateEngine templateEngine = new MustacheTemplateEngine();
final InvoiceFormatterFactory factory = new DefaultInvoiceFormatterFactory();
- g = new HtmlInvoiceGenerator(factory, templateEngine, config, null);
+ g = new HtmlInvoiceGenerator(factory, templateEngine, config, null, resourceBundleFactory, null);
}
@Test(groups = "fast")
public void testGenerateInvoice() throws Exception {
- final HtmlInvoice output = g.generateInvoice(createAccount(), createInvoice(), false);
+ final HtmlInvoice output = g.generateInvoice(createAccount(), createInvoice(), false, internalCallContext);
Assert.assertNotNull(output);
Assert.assertNotNull(output.getBody());
Assert.assertEquals(output.getSubject(), "Your invoice");
@@ -68,7 +68,7 @@ public class TestHtmlInvoiceGenerator extends InvoiceTestSuiteNoDB {
@Test(groups = "fast")
public void testGenerateEmptyInvoice() throws Exception {
final Invoice invoice = Mockito.mock(Invoice.class);
- final HtmlInvoice output = g.generateInvoice(createAccount(), invoice, false);
+ final HtmlInvoice output = g.generateInvoice(createAccount(), invoice, false, internalCallContext);
Assert.assertNotNull(output);
Assert.assertNotNull(output.getBody());
Assert.assertEquals(output.getSubject(), "Your invoice");
@@ -76,7 +76,7 @@ public class TestHtmlInvoiceGenerator extends InvoiceTestSuiteNoDB {
@Test(groups = "fast")
public void testGenerateNullInvoice() throws Exception {
- final HtmlInvoice output = g.generateInvoice(createAccount(), null, false);
+ final HtmlInvoice output = g.generateInvoice(createAccount(), null, false, internalCallContext);
Assert.assertNull(output);
}
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueEmailGenerator.java b/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueEmailGenerator.java
index 8cb44b2..d7fd94e 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueEmailGenerator.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueEmailGenerator.java
@@ -16,7 +16,9 @@
package org.killbill.billing.overdue.applicator;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
@@ -25,7 +27,9 @@ import org.killbill.billing.overdue.api.OverdueState;
import org.killbill.billing.overdue.applicator.formatters.OverdueEmailFormatterFactory;
import org.killbill.billing.overdue.config.api.BillingState;
import org.killbill.billing.util.email.templates.TemplateEngine;
+import org.killbill.billing.util.io.IOUtils;
+import com.google.common.io.CharSource;
import com.google.inject.Inject;
public class OverdueEmailGenerator {
@@ -50,6 +54,7 @@ public class OverdueEmailGenerator {
data.put("nextOverdueState", nextOverdueState);
// TODO single template for all languages for now
- return templateEngine.executeTemplate(nextOverdueState.getEmailNotification().getTemplateName(), data);
+ final InputStream input = new FileInputStream(nextOverdueState.getEmailNotification().getTemplateName());
+ return templateEngine.executeTemplateText(IOUtils.toString(input), data);
}
}
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
index 2010e09..f4204ac 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestCatalog.java
@@ -29,8 +29,19 @@ import org.killbill.billing.client.model.Product;
import org.testng.Assert;
import org.testng.annotations.Test;
+import com.google.common.io.Resources;
+
public class TestCatalog extends TestJaxrsBase {
+ @Test(groups = "slow", description = "Upload and retrieve a per tenant catalog")
+ public void testMultiTenantCatalog() throws Exception {
+ final String catalogPath = Resources.getResource("SpyCarBasic.xml").getPath();
+ killBillClient.uploadXMLCatalog(catalogPath, createdBy, reason, comment);
+
+ final String catalog = killBillClient.getXMLCatalog();
+ Assert.assertNotNull(catalog);
+ }
+
@Test(groups = "slow", description = "Can retrieve a simplified version of the catalog")
public void testCatalogSimple() throws Exception {
final Set<String> allBasePlans = new HashSet<String>();
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestOverdue.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestOverdue.java
index d9d9898..6685955 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestOverdue.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestOverdue.java
@@ -31,11 +31,22 @@ import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.collect.Ordering;
+import com.google.common.io.Resources;
import static org.testng.Assert.assertEquals;
public class TestOverdue extends TestJaxrsBase {
+ @Test(groups = "slow", description = "Upload and retrieve a per tenant overdue config")
+ public void testMultiTenantOverdueConfig() throws Exception {
+ final String overdueConfigPath = Resources.getResource("overdue.xml").getPath();
+ killBillClient.uploadXMLOverdueConfig(overdueConfigPath, createdBy, reason, comment);
+
+ final String overdueConfig = killBillClient.getXMLOverdueConfig();
+ Assert.assertNotNull(overdueConfig);
+ }
+
+
@Test(groups = "slow", description = "Can retrieve the account overdue status")
public void testOverdueStatus() throws Exception {
// Create an account without a payment method
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 fa9454b..bc46459 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
@@ -18,6 +18,7 @@
package org.killbill.billing.tenant.api;
import java.util.List;
+import java.util.Locale;
import javax.inject.Inject;
import javax.inject.Named;
@@ -44,6 +45,49 @@ public class DefaultTenantInternalApi implements TenantInternalApi {
@Override
public String getTenantOverdueConfig(final InternalTenantContext tenantContext) {
final List<String> values = tenantDao.getTenantValueForKey(TenantKey.OVERDUE_CONFIG.toString(), tenantContext);
- return values.isEmpty() ? null : values.get(0);
+ return getUniqueValue(values, "overdue config", tenantContext);
+ }
+
+ @Override
+ public String getInvoiceTemplate(final Locale locale, final InternalTenantContext tenantContext) {
+ final List<String> values = tenantDao.getTenantValueForKey(getKeyFromLocale(TenantKey.INVOICE_TEMPLATE_.toString(), locale), 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);
+ 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);
+ 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);
+ return getUniqueValue(values, "catalog translation", tenantContext);
+ }
+
+ private String getUniqueValue(final List<String> values, final String msg, final InternalTenantContext tenantContext) {
+ if (values.isEmpty()) {
+ return null;
+ }
+ if (values.size() > 1) {
+ throw new IllegalStateException(String.format("Unexpected number of values %d for %s and tenant %d",
+ values.size(), msg, tenantContext.getTenantRecordId()));
+ }
+ 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/email/templates/MustacheTemplateEngine.java b/util/src/main/java/org/killbill/billing/util/email/templates/MustacheTemplateEngine.java
index 10960b3..b914220 100644
--- a/util/src/main/java/org/killbill/billing/util/email/templates/MustacheTemplateEngine.java
+++ b/util/src/main/java/org/killbill/billing/util/email/templates/MustacheTemplateEngine.java
@@ -16,39 +16,16 @@
package org.killbill.billing.util.email.templates;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URISyntaxException;
import java.util.Map;
-import org.killbill.billing.util.io.IOUtils;
-import org.killbill.xmlloader.UriAccessor;
-import com.google.common.annotations.VisibleForTesting;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
public class MustacheTemplateEngine implements TemplateEngine {
@Override
- public String executeTemplate(final String templateName, final Map<String, Object> data) throws IOException {
- final String templateText = getTemplateText(templateName);
- return executeTemplateText(templateText, data);
- }
-
- @VisibleForTesting
public String executeTemplateText(final String templateText, final Map<String, Object> data) {
final Template template = Mustache.compiler().compile(templateText);
return template.execute(data);
}
-
- private String getTemplateText(final String templateName) throws IOException {
- final InputStream templateStream;
- try {
- templateStream = UriAccessor.accessUri(templateName);
- } catch (URISyntaxException e) {
- throw new IOException(e);
- }
-
- return IOUtils.toString(templateStream);
- }
}
diff --git a/util/src/main/java/org/killbill/billing/util/email/templates/TemplateEngine.java b/util/src/main/java/org/killbill/billing/util/email/templates/TemplateEngine.java
index 2854b39..b662127 100644
--- a/util/src/main/java/org/killbill/billing/util/email/templates/TemplateEngine.java
+++ b/util/src/main/java/org/killbill/billing/util/email/templates/TemplateEngine.java
@@ -16,9 +16,10 @@
package org.killbill.billing.util.email.templates;
-import java.io.IOException;
import java.util.Map;
public interface TemplateEngine {
- public String executeTemplate(String templateName, Map<String, Object> data) throws IOException;
+
+ public String executeTemplateText(final String templateText, final Map<String, Object> data);
+
}
diff --git a/util/src/main/java/org/killbill/billing/util/template/translation/DefaultCatalogTranslator.java b/util/src/main/java/org/killbill/billing/util/template/translation/DefaultCatalogTranslator.java
index 0343da3..4193b91 100644
--- a/util/src/main/java/org/killbill/billing/util/template/translation/DefaultCatalogTranslator.java
+++ b/util/src/main/java/org/killbill/billing/util/template/translation/DefaultCatalogTranslator.java
@@ -16,21 +16,12 @@
package org.killbill.billing.util.template.translation;
-import com.google.inject.Inject;
+import java.util.ResourceBundle;
public class DefaultCatalogTranslator extends DefaultTranslatorBase {
- @Inject
- public DefaultCatalogTranslator(final TranslatorConfig config) {
- super(config);
- }
-
- @Override
- protected String getBundlePath() {
- return config.getCatalogBundlePath();
- }
- @Override
- protected String getTranslationType() {
- return "catalog";
+ public DefaultCatalogTranslator(final ResourceBundle bundle,
+ final ResourceBundle defaultBundle) {
+ super(bundle, defaultBundle);
}
}
diff --git a/util/src/main/java/org/killbill/billing/util/template/translation/DefaultTranslatorBase.java b/util/src/main/java/org/killbill/billing/util/template/translation/DefaultTranslatorBase.java
index 4516415..dfe8e51 100644
--- a/util/src/main/java/org/killbill/billing/util/template/translation/DefaultTranslatorBase.java
+++ b/util/src/main/java/org/killbill/billing/util/template/translation/DefaultTranslatorBase.java
@@ -16,104 +16,39 @@
package org.killbill.billing.util.template.translation;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URISyntaxException;
-import java.util.Locale;
-import java.util.MissingResourceException;
-import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
-import org.killbill.xmlloader.UriAccessor;
+import javax.annotation.Nullable;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.killbill.billing.util.LocaleUtils;
-
-import com.google.inject.Inject;
-
public abstract class DefaultTranslatorBase implements Translator {
- protected final TranslatorConfig config;
protected final Logger log = LoggerFactory.getLogger(DefaultTranslatorBase.class);
- @Inject
- public DefaultTranslatorBase(final TranslatorConfig config) {
- this.config = config;
- }
-
- protected abstract String getBundlePath();
+ private final ResourceBundle bundle;
+ private final ResourceBundle defaultBundle;
- /*
- * string used for exception handling
- */
- protected abstract String getTranslationType();
+ public DefaultTranslatorBase(@Nullable final ResourceBundle bundle,
+ @Nullable final ResourceBundle defaultBundle) {
+ this.bundle = bundle;
+ this.defaultBundle = defaultBundle;
+ }
@Override
- public String getTranslation(final Locale locale, final String originalText) {
- final String bundlePath = getBundlePath();
- ResourceBundle bundle = getBundle(locale, bundlePath);
-
+ public String getTranslation(final String originalText) {
+ if (originalText == null) {
+ return null;
+ }
if ((bundle != null) && (bundle.containsKey(originalText))) {
return bundle.getString(originalText);
} else {
- if (config.getDefaultLocale() == null) {
- log.debug("No default locale configured, returning original text");
- return originalText;
- }
-
- final Locale defaultLocale = LocaleUtils.toLocale(config.getDefaultLocale());
- try {
- bundle = getBundle(defaultLocale, bundlePath);
-
- if ((bundle != null) && (bundle.containsKey(originalText))) {
- return bundle.getString(originalText);
- } else {
- return originalText;
- }
- } catch (MissingResourceException mrex) {
- log.warn("Missing translation bundle for locale {}", defaultLocale);
- return originalText;
- }
- }
- }
-
- private ResourceBundle getBundle(final Locale locale, final String bundlePath) {
- try {
- // Try to load the bundle from the classpath first
- return ResourceBundle.getBundle(bundlePath, locale);
- } catch (MissingResourceException ignored) {
- }
-
- // Try to load it from a properties file
- final String propertiesFileNameWithCountry = bundlePath + "_" + locale.getLanguage() + "_" + locale.getCountry() + ".properties";
- ResourceBundle bundle = getBundleFromPropertiesFile(propertiesFileNameWithCountry);
- if (bundle != null) {
- return bundle;
- } else {
- final String propertiesFileName = bundlePath + "_" + locale.getLanguage() + ".properties";
- bundle = getBundleFromPropertiesFile(propertiesFileName);
- }
-
- return bundle;
- }
-
- private ResourceBundle getBundleFromPropertiesFile(final String propertiesFileName) {
- try {
- final InputStream inputStream = UriAccessor.accessUri(propertiesFileName);
- if (inputStream == null) {
- return null;
+ if ((defaultBundle != null) && (defaultBundle.containsKey(originalText))) {
+ return defaultBundle.getString(originalText);
} else {
- return new PropertyResourceBundle(inputStream);
+ return originalText;
}
- } catch (IllegalArgumentException iae) {
- return null;
- } catch (MissingResourceException mrex) {
- return null;
- } catch (URISyntaxException e) {
- return null;
- } catch (IOException e) {
- return null;
}
}
}
diff --git a/util/src/test/java/org/killbill/billing/mock/MockInvoiceFormatterFactory.java b/util/src/test/java/org/killbill/billing/mock/MockInvoiceFormatterFactory.java
index 7efaaf2..44fd9f0 100644
--- a/util/src/test/java/org/killbill/billing/mock/MockInvoiceFormatterFactory.java
+++ b/util/src/test/java/org/killbill/billing/mock/MockInvoiceFormatterFactory.java
@@ -18,15 +18,18 @@ package org.killbill.billing.mock;
import java.util.Locale;
+import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.currency.api.CurrencyConversionApi;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.formatters.InvoiceFormatter;
import org.killbill.billing.invoice.api.formatters.InvoiceFormatterFactory;
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory;
import org.killbill.billing.util.template.translation.TranslatorConfig;
public class MockInvoiceFormatterFactory implements InvoiceFormatterFactory {
+
@Override
- public InvoiceFormatter createInvoiceFormatter(final TranslatorConfig config, final Invoice invoice, final Locale locale, CurrencyConversionApi currencyConversionApi) {
+ public InvoiceFormatter createInvoiceFormatter(final TranslatorConfig config, final Invoice invoice, final Locale locale, final CurrencyConversionApi currencyConversionApi, final ResourceBundleFactory bundleFactory, final InternalTenantContext context) {
return null;
}
}
diff --git a/util/src/test/java/org/killbill/billing/util/email/DefaultCatalogTranslationTest.java b/util/src/test/java/org/killbill/billing/util/email/DefaultCatalogTranslationTest.java
index f281f3d..6af5d3e 100644
--- a/util/src/test/java/org/killbill/billing/util/email/DefaultCatalogTranslationTest.java
+++ b/util/src/test/java/org/killbill/billing/util/email/DefaultCatalogTranslationTest.java
@@ -14,18 +14,24 @@ package org.killbill.billing.util.email;/*
* under the License.
*/
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
import java.util.Locale;
import java.util.Map;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
-import org.skife.config.ConfigSource;
-import org.skife.config.ConfigurationObjectFactory;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory;
import org.killbill.billing.util.UtilTestSuiteNoDB;
import org.killbill.billing.util.template.translation.DefaultCatalogTranslator;
import org.killbill.billing.util.template.translation.Translator;
import org.killbill.billing.util.template.translation.TranslatorConfig;
+import org.killbill.xmlloader.UriAccessor;
+import org.skife.config.ConfigSource;
+import org.skife.config.ConfigurationObjectFactory;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
@@ -33,70 +39,61 @@ import static org.testng.Assert.assertEquals;
public class DefaultCatalogTranslationTest extends UtilTestSuiteNoDB {
- private Translator translation;
-
@Override
@BeforeClass(groups = "fast")
public void beforeClass() throws Exception {
super.beforeClass();
- final ConfigSource configSource = new ConfigSource() {
- private final Map<String, String> properties = ImmutableMap.<String, String>of("org.killbill.template.invoiceFormatterFactoryClass",
- "org.killbill.billing.mock.MockInvoiceFormatterFactory");
-
- @Override
- public String getString(final String propertyName) {
- return properties.get(propertyName);
- }
- };
-
- final TranslatorConfig config = new ConfigurationObjectFactory(configSource).build(TranslatorConfig.class);
- translation = new DefaultCatalogTranslator(config);
+ }
+
+ private ResourceBundle getBundle(final Locale locale) throws IOException, URISyntaxException {
+ final String propertiesFileNameWithCountry = "org/killbill/billing/util/template/translation/CatalogTranslation" + "_" + locale.getLanguage() + "_" + locale.getCountry() + ".properties";
+ final InputStream inputStream = UriAccessor.accessUri(propertiesFileNameWithCountry);
+ if (inputStream == null) {
+ return null;
+ } else {
+ return new PropertyResourceBundle(inputStream);
+ }
}
@Test(groups = "fast")
- public void testInitialization() {
+ public void testBundle_us() throws IOException, URISyntaxException {
final String shotgunMonthly = "shotgun-monthly";
final String shotgunAnnual = "shotgun-annual";
final String badText = "Bad text";
- assertEquals(translation.getTranslation(Locale.US, shotgunMonthly), "Monthly shotgun plan");
- assertEquals(translation.getTranslation(Locale.US, shotgunAnnual), "Annual shotgun plan");
- assertEquals(translation.getTranslation(Locale.US, badText), badText);
-
- assertEquals(translation.getTranslation(Locale.CANADA_FRENCH, shotgunMonthly), "Fusil de chasse mensuel");
- assertEquals(translation.getTranslation(Locale.CANADA_FRENCH, shotgunAnnual), "Fusil de chasse annuel");
- assertEquals(translation.getTranslation(Locale.CANADA_FRENCH, badText), badText);
+ final ResourceBundle bundle_en_US = getBundle(Locale.US);
+ final DefaultCatalogTranslator translation = new DefaultCatalogTranslator(bundle_en_US, null);
- assertEquals(translation.getTranslation(Locale.CHINA, shotgunMonthly), "Monthly shotgun plan");
- assertEquals(translation.getTranslation(Locale.CHINA, shotgunAnnual), "Annual shotgun plan");
- assertEquals(translation.getTranslation(Locale.CHINA, badText), badText);
+ assertEquals(translation.getTranslation(shotgunMonthly), "Monthly shotgun plan");
+ assertEquals(translation.getTranslation(shotgunAnnual), "Annual shotgun plan");
+ assertEquals(translation.getTranslation(badText), badText);
}
@Test(groups = "fast")
- public void testExistingTranslation() {
- // If the translation exists, return the translation
- final String originalText = "shotgun-monthly";
- assertEquals(translation.getTranslation(Locale.US, originalText), "Monthly shotgun plan");
- }
+ public void testBundle_ca_fr() throws IOException, URISyntaxException {
+ final String shotgunMonthly = "shotgun-monthly";
+ final String shotgunAnnual = "shotgun-annual";
+ final String badText = "Bad text";
- @Test(groups = "fast")
- public void testMissingTranslation() {
- // If the translation is missing from the file, return the original text
- final String originalText = "missing translation";
- assertEquals(translation.getTranslation(Locale.US, originalText), originalText);
- }
+ final ResourceBundle bundle_ca_fr = getBundle(Locale.CANADA_FRENCH);
+ final DefaultCatalogTranslator translation = new DefaultCatalogTranslator(bundle_ca_fr, null);
- @Test(groups = "fast")
- public void testMissingTranslationFileWithEnglishText() {
- // If the translation file doesn't exist, return the "English" translation
- final String originalText = "shotgun-monthly";
- assertEquals(translation.getTranslation(Locale.CHINA, originalText), "Monthly shotgun plan");
+ assertEquals(translation.getTranslation(shotgunMonthly), "Fusil de chasse mensuel");
+ assertEquals(translation.getTranslation(shotgunAnnual), "Fusil de chasse annuel");
+ assertEquals(translation.getTranslation(badText), badText);
}
@Test(groups = "fast")
- public void testMissingFileAndText() {
- // If the file is missing, and the "English" translation is missing, return the original text
- final String originalText = "missing translation";
- assertEquals(translation.getTranslation(Locale.CHINA, originalText), originalText);
+ public void testBundle_ch() throws IOException, URISyntaxException {
+ final String shotgunMonthly = "shotgun-monthly";
+ final String shotgunAnnual = "shotgun-annual";
+ final String badText = "Bad text";
+
+ final DefaultCatalogTranslator translation = new DefaultCatalogTranslator(null, null);
+
+ assertEquals(translation.getTranslation(shotgunMonthly), shotgunMonthly);
+ assertEquals(translation.getTranslation(shotgunAnnual), shotgunAnnual);
+ assertEquals(translation.getTranslation(badText), badText);
}
+
}
diff --git a/util/src/test/java/org/killbill/billing/util/template/translation/TestDefaultTranslatorBase.java b/util/src/test/java/org/killbill/billing/util/template/translation/TestDefaultTranslatorBase.java
index eff1e43..7ac4cd6 100644
--- a/util/src/test/java/org/killbill/billing/util/template/translation/TestDefaultTranslatorBase.java
+++ b/util/src/test/java/org/killbill/billing/util/template/translation/TestDefaultTranslatorBase.java
@@ -16,7 +16,7 @@
package org.killbill.billing.util.template.translation;
-import java.util.Locale;
+import java.util.ResourceBundle;
import java.util.UUID;
import org.mockito.Mockito;
@@ -29,25 +29,16 @@ public class TestDefaultTranslatorBase extends UtilTestSuiteNoDB {
private final class TestTranslatorBase extends DefaultTranslatorBase {
- public TestTranslatorBase(final TranslatorConfig config) {
- super(config);
+ public TestTranslatorBase(final TranslatorConfig config, final ResourceBundle bundle) {
+ super(bundle, bundle);
}
- @Override
- protected String getBundlePath() {
- return UUID.randomUUID().toString();
- }
-
- @Override
- protected String getTranslationType() {
- return UUID.randomUUID().toString();
- }
}
@Test(groups = "fast")
public void testResourceDoesNotExist() throws Exception {
- final TestTranslatorBase translator = new TestTranslatorBase(Mockito.mock(TranslatorConfig.class));
+ final TestTranslatorBase translator = new TestTranslatorBase(Mockito.mock(TranslatorConfig.class), Mockito.mock(ResourceBundle.class));
final String originalText = UUID.randomUUID().toString();
- Assert.assertEquals(translator.getTranslation(Locale.FRANCE, originalText), originalText);
+ Assert.assertEquals(translator.getTranslation(originalText), originalText);
}
}