killbill-memoizeit

jaxrs: enhance support for load balancers See https://github.com/killbill/killbill/issues/566

12/28/2016 1:29:32 PM

Changes

Details

diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
index 982e965..586d769 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
@@ -356,7 +356,7 @@ public class AccountResource extends JaxRsResourceBase {
 
         final AccountData data = json.toAccountData();
         final Account account = accountUserApi.createAccount(data, context.createContext(createdBy, reason, comment, request));
-        return uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccount", account.getId());
+        return uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccount", account.getId(), request);
     }
 
     @TimedResource
@@ -783,7 +783,7 @@ public class AccountResource extends JaxRsResourceBase {
                 createPurchaseForInvoice(account, invoice.getId(), invoice.getBalance(), paymentMethodId, false, null, null, pluginProperties, callContext);
             }
         }
-        return uriBuilder.buildResponse(PaymentMethodResource.class, "getPaymentMethod", paymentMethodId, uriInfo.getBaseUri().toString());
+        return uriBuilder.buildResponse(uriInfo, PaymentMethodResource.class, "getPaymentMethod", paymentMethodId, request);
     }
 
     @TimedResource
@@ -930,7 +930,7 @@ public class AccountResource extends JaxRsResourceBase {
         final CallContext callContext = context.createContext(createdBy, reason, comment, request);
         final Account account = accountUserApi.getAccountByKey(externalKey, callContext);
 
-        return processPayment(json, account, paymentMethodIdStr, paymentControlPluginNames, pluginPropertiesString, uriInfo, callContext);
+        return processPayment(json, account, paymentMethodIdStr, paymentControlPluginNames, pluginPropertiesString, uriInfo, callContext, request);
     }
 
     @TimedResource(name = "processPayment")
@@ -961,7 +961,7 @@ public class AccountResource extends JaxRsResourceBase {
         final CallContext callContext = context.createContext(createdBy, reason, comment, request);
         final Account account = accountUserApi.getAccountById(accountId, callContext);
 
-        return processPayment(json, account, paymentMethodIdStr, paymentControlPluginNames, pluginPropertiesString, uriInfo, callContext);
+        return processPayment(json, account, paymentMethodIdStr, paymentControlPluginNames, pluginPropertiesString, uriInfo, callContext, request);
     }
 
     private Response processPayment(final PaymentTransactionJson json,
@@ -970,7 +970,8 @@ public class AccountResource extends JaxRsResourceBase {
                                     final List<String> paymentControlPluginNames,
                                     final List<String> pluginPropertiesString,
                                     final UriInfo uriInfo,
-                                    final CallContext callContext) throws PaymentApiException {
+                                    final CallContext callContext,
+                                    final HttpServletRequest request) throws PaymentApiException {
         verifyNonNullOrEmpty(json, "PaymentTransactionJson body should be specified");
         verifyNonNullOrEmpty(json.getTransactionType(), "PaymentTransactionJson transactionType needs to be set",
                              json.getAmount(), "PaymentTransactionJson amount needs to be set");
@@ -993,7 +994,7 @@ public class AccountResource extends JaxRsResourceBase {
                                                                                    json != null ? json.getTransactionType() : null);
             // If transaction was already completed, return early (See #626)
             if (pendingOrSuccessTransaction.getTransactionStatus() == TransactionStatus.SUCCESS) {
-                return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", pendingOrSuccessTransaction.getPaymentId());
+                return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", pendingOrSuccessTransaction.getPaymentId(), request);
             }
 
             paymentMethodId = initialPayment.getPaymentMethodId();
@@ -1025,7 +1026,7 @@ public class AccountResource extends JaxRsResourceBase {
             default:
                 return Response.status(Status.PRECONDITION_FAILED).entity("TransactionType " + transactionType + " is not allowed for an account").build();
         }
-        return createPaymentResponse(uriInfo, result, transactionType, json.getTransactionExternalKey());
+        return createPaymentResponse(uriInfo, result, transactionType, json.getTransactionExternalKey(), request);
     }
 
     /*
@@ -1130,7 +1131,7 @@ public class AccountResource extends JaxRsResourceBase {
                                        @javax.ws.rs.core.Context final HttpServletRequest request,
                                        @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(UUID.fromString(id), customFields, context.createContext(createdBy, reason,
-                                             comment, request), uriInfo);
+                                             comment, request), uriInfo, request);
     }
 
     @TimedResource
@@ -1203,7 +1204,7 @@ public class AccountResource extends JaxRsResourceBase {
                                @javax.ws.rs.core.Context final UriInfo uriInfo,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(UUID.fromString(id), tagList, uriInfo,
-                                context.createContext(createdBy, reason, comment, request));
+                                context.createContext(createdBy, reason, comment, request), request);
     }
 
     @TimedResource
@@ -1303,7 +1304,7 @@ public class AccountResource extends JaxRsResourceBase {
             accountUserApi.addEmail(accountId, json.toAccountEmail(UUIDs.randomUUID()), callContext);
         }
 
-        return uriBuilder.buildResponse(uriInfo, AccountResource.class, "getEmails", json.getAccountId());
+        return uriBuilder.buildResponse(uriInfo, AccountResource.class, "getEmails", json.getAccountId(), request);
     }
 
     @TimedResource
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java
index 04e39d5..c54164a 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java
@@ -321,7 +321,7 @@ public class BundleResource extends JaxRsResourceBase {
                                        @javax.ws.rs.core.Context final HttpServletRequest request,
                                        @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(UUID.fromString(id), customFields,
-                                        context.createContext(createdBy, reason, comment, request), uriInfo);
+                                        context.createContext(createdBy, reason, comment, request), uriInfo, request);
     }
 
     @TimedResource
@@ -389,7 +389,7 @@ public class BundleResource extends JaxRsResourceBase {
         final LocalDate inputLocalDate = toLocalDate(requestedDate);
 
         final UUID newBundleId = entitlementApi.transferEntitlementsOverrideBillingPolicy(bundle.getAccountId(), UUID.fromString(json.getAccountId()), bundle.getExternalKey(), inputLocalDate, policy, pluginProperties, callContext);
-        return uriBuilder.buildResponse(BundleResource.class, "getBundle", newBundleId, uriInfo.getBaseUri().toString());
+        return uriBuilder.buildResponse(uriInfo, BundleResource.class, "getBundle", newBundleId, request);
     }
 
     @TimedResource
@@ -407,7 +407,7 @@ public class BundleResource extends JaxRsResourceBase {
                                @javax.ws.rs.core.Context final UriInfo uriInfo,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(UUID.fromString(id), tagList, uriInfo,
-                                context.createContext(createdBy, reason, comment, request));
+                                context.createContext(createdBy, reason, comment, request), request);
     }
 
     @TimedResource
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
index 22f7568..3f842fe 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
@@ -36,9 +36,7 @@ import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.killbill.billing.account.api.AccountUserApi;
 import org.killbill.billing.catalog.StandaloneCatalog;
-import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
 import org.killbill.billing.catalog.VersionedCatalog;
-import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogUserApi;
 import org.killbill.billing.catalog.api.Listing;
@@ -113,7 +111,7 @@ public class CatalogResource extends JaxRsResourceBase {
                                      @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
         final CallContext callContext = context.createContext(createdBy, reason, comment, request);
         catalogUserApi.uploadCatalog(catalogXML, callContext);
-        return uriBuilder.buildResponse(uriInfo, CatalogResource.class, null, null);
+        return uriBuilder.buildResponse(uriInfo, CatalogResource.class, null, null, request);
     }
 
     @TimedResource
@@ -219,7 +217,7 @@ public class CatalogResource extends JaxRsResourceBase {
                                                                           simplePlan.getTrialTimeUnit(),
                                                                           simplePlan.getAvailableBaseProducts());
         catalogUserApi.addSimplePlan(desc, clock.getUTCNow(), callContext);
-        return uriBuilder.buildResponse(uriInfo, CatalogResource.class, null, null);
+        return uriBuilder.buildResponse(uriInfo, CatalogResource.class, null, null, request);
     }
 
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CreditResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CreditResource.java
index b6d005f..17e2c9f 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CreditResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CreditResource.java
@@ -131,7 +131,7 @@ public class CreditResource extends JaxRsResourceBase {
                                                  account.getCurrency(), autoCommit, json.getDescription(), callContext);
         }
 
-        return uriBuilder.buildResponse(uriInfo, CreditResource.class, "getCredit", credit.getId());
+        return uriBuilder.buildResponse(uriInfo, CreditResource.class, "getCredit", credit.getId(), request);
     }
 
     @Override
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
index ff2ed5a..e5249e9 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
@@ -57,7 +57,6 @@ import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
 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.PaymentMethod;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.util.UUIDs;
 import org.killbill.billing.util.api.AuditUserApi;
@@ -200,7 +199,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
                                                                pluginProperties, createInvoicePaymentControlPluginApiPaymentOptions(false), callContext);
         }
 
-        return uriBuilder.buildResponse(InvoicePaymentResource.class, "getInvoicePayment", result.getId(), uriInfo.getBaseUri().toString());
+        return uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId(), request);
     }
 
     @TimedResource
@@ -229,7 +228,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
 
         final Payment result = paymentApi.createChargebackWithPaymentControl(account, payment.getId(), json.getAmount(), account.getCurrency(),
                                                                                    transactionExternalKey, createInvoicePaymentControlPluginApiPaymentOptions(false), callContext);
-        return uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId());
+        return uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId(), request);
     }
 
     @TimedResource
@@ -256,7 +255,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
         final Account account = accountUserApi.getAccountById(payment.getAccountId(), callContext);
 
         final Payment result = paymentApi.createChargebackReversalWithPaymentControl(account, payment.getId(), json.getTransactionExternalKey(), createInvoicePaymentControlPluginApiPaymentOptions(false), callContext);
-        return uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId());
+        return uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId(), request);
     }
 
     @TimedResource
@@ -286,7 +285,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
                                        @javax.ws.rs.core.Context final HttpServletRequest request,
                                        @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(UUID.fromString(id), customFields,
-                                        context.createContext(createdBy, reason, comment, request), uriInfo);
+                                        context.createContext(createdBy, reason, comment, request), uriInfo, request);
     }
 
     @TimedResource
@@ -340,7 +339,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
                                @javax.ws.rs.core.Context final UriInfo uriInfo,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(UUID.fromString(id), tagList, uriInfo,
-                                context.createContext(createdBy, reason, comment, request));
+                                context.createContext(createdBy, reason, comment, request), request);
     }
 
     @TimedResource
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 2b6f285..cd70288 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
@@ -93,7 +93,6 @@ 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.UUIDs;
 import org.killbill.billing.util.api.AuditUserApi;
 import org.killbill.billing.util.api.CustomFieldApiException;
 import org.killbill.billing.util.api.CustomFieldUserApi;
@@ -311,7 +310,7 @@ public class InvoiceResource extends JaxRsResourceBase {
         try {
             final Invoice generatedInvoice = invoiceApi.triggerInvoiceGeneration(UUID.fromString(accountId), inputDate, null,
                                                                                  callContext);
-            return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", generatedInvoice.getId());
+            return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", generatedInvoice.getId(), request);
         } catch (InvoiceApiException e) {
             if (e.getCode() == ErrorCode.INVOICE_NOTHING_TO_DO.getCode()) {
                 return Response.status(Status.NOT_FOUND).build();
@@ -341,7 +340,7 @@ public class InvoiceResource extends JaxRsResourceBase {
         final Iterable<InvoiceItem> sanitizedInvoiceItems = validateSanitizeAndTranformInputItems(account.getCurrency(), items);
         final LocalDate resolvedTargetDate =  toLocalDateDefaultToday(account, targetDate, callContext);
         final UUID invoiceId = invoiceApi.createMigrationInvoice(UUID.fromString(accountId), resolvedTargetDate, sanitizedInvoiceItems, callContext);
-        return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", invoiceId);
+        return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", invoiceId, request);
     }
 
 
@@ -475,7 +474,7 @@ public class InvoiceResource extends JaxRsResourceBase {
                                                                     callContext);
         }
 
-        return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", adjustmentItem.getInvoiceId());
+        return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", adjustmentItem.getInvoiceId(), request);
     }
 
     @TimedResource
@@ -663,7 +662,7 @@ public class InvoiceResource extends JaxRsResourceBase {
         final Payment result = createPurchaseForInvoice(account, invoiceId, payment.getPurchasedAmount(), paymentMethodId, externalPayment,
                                                         (payment.getPaymentExternalKey() != null) ? payment.getPaymentExternalKey() : null, null, pluginProperties, callContext);
         return result != null ?
-               uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId()) :
+               uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId(), request) :
                Response.status(Status.NO_CONTENT).build();
     }
 
@@ -878,7 +877,7 @@ public class InvoiceResource extends JaxRsResourceBase {
             }
         }
         tenantApi.addTenantKeyValue(tenantKeyStr, templateResource, callContext);
-        return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, getMethodStr, localeStr);
+        return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, getMethodStr, localeStr, request);
     }
 
     private Response getTemplateResource(@Nullable final String localeStr,
@@ -919,7 +918,7 @@ public class InvoiceResource extends JaxRsResourceBase {
                                        @javax.ws.rs.core.Context final HttpServletRequest request,
                                        @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(UUID.fromString(id), customFields,
-                                        context.createContext(createdBy, reason, comment, request), uriInfo);
+                                        context.createContext(createdBy, reason, comment, request), uriInfo, request);
     }
 
     @TimedResource
@@ -971,7 +970,7 @@ public class InvoiceResource extends JaxRsResourceBase {
                                @javax.ws.rs.core.Context final UriInfo uriInfo,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(UUID.fromString(id), tagList, uriInfo,
-                                context.createContext(createdBy, reason, comment, request));
+                                context.createContext(createdBy, reason, comment, request), request);
     }
 
     @TimedResource
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
index 591dbfc..74dabf6 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxRsResourceBase.java
@@ -78,7 +78,6 @@ import org.killbill.billing.payment.api.PaymentTransaction;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.api.TransactionStatus;
 import org.killbill.billing.payment.api.TransactionType;
-import org.killbill.billing.util.UUIDs;
 import org.killbill.billing.util.api.AuditUserApi;
 import org.killbill.billing.util.api.CustomFieldApiException;
 import org.killbill.billing.util.api.CustomFieldUserApi;
@@ -213,11 +212,12 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
     protected Response createTags(final UUID id,
                                   final String tagList,
                                   final UriInfo uriInfo,
-                                  final CallContext context) throws TagApiException {
+                                  final CallContext context,
+                                  final HttpServletRequest request) throws TagApiException {
         final Collection<UUID> input = getTagDefinitionUUIDs(tagList);
         tagUserApi.addTags(id, getObjectType(), input, context);
         // TODO This will always return 201, even if some (or all) tags already existed (in which case we don't do anything)
-        return uriBuilder.buildResponse(this.getClass(), "getTags", id, uriInfo.getBaseUri().toString());
+        return uriBuilder.buildResponse(uriInfo, this.getClass(), "getTags", id, request);
     }
 
     protected Collection<UUID> getTagDefinitionUUIDs(final String tagList) {
@@ -255,7 +255,8 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
     protected Response createCustomFields(final UUID id,
                                           final List<CustomFieldJson> customFields,
                                           final CallContext context,
-                                          final UriInfo uriInfo) throws CustomFieldApiException {
+                                          final UriInfo uriInfo,
+                                          final HttpServletRequest request) throws CustomFieldApiException {
         final LinkedList<CustomField> input = new LinkedList<CustomField>();
         for (final CustomFieldJson cur : customFields) {
             verifyNonNullOrEmpty(cur.getName(), "CustomFieldJson name needs to be set");
@@ -264,7 +265,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         }
 
         customFieldUserApi.addCustomFields(input, context);
-        return uriBuilder.buildResponse(uriInfo, this.getClass(), "getCustomFields", id);
+        return uriBuilder.buildResponse(uriInfo, this.getClass(), "getCustomFields", id, request);
     }
 
     /**
@@ -554,7 +555,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         }
     }
 
-    protected Response createPaymentResponse(final UriInfo uriInfo, final Payment payment, final TransactionType transactionType, @Nullable final String transactionExternalKey) {
+    protected Response createPaymentResponse(final UriInfo uriInfo, final Payment payment, final TransactionType transactionType, @Nullable final String transactionExternalKey, final HttpServletRequest request) {
         final PaymentTransaction createdTransaction = findCreatedTransaction(payment, transactionType, transactionExternalKey);
         Preconditions.checkNotNull(createdTransaction, "No transaction of type '%s' found", transactionType);
 
@@ -563,7 +564,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         switch (createdTransaction.getTransactionStatus()) {
             case PENDING:
             case SUCCESS:
-                return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", payment.getId());
+                return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", payment.getId(), request);
             case PAYMENT_FAILURE:
                 // 402 - Payment Required
                 responseBuilder = Response.status(402);
@@ -590,7 +591,7 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
                 exception = createBillingException("This should never have happened!!!");
         }
         addExceptionToResponse(responseBuilder, exception);
-        return responseBuilder.location(getPaymentLocation(uriInfo, payment)).build();
+        return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", payment.getId(), request);
     }
 
     private void addExceptionToResponse(final ResponseBuilder responseBuilder, final BillingExceptionJson exception) {
@@ -608,10 +609,6 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         return exception;
     }
 
-    private URI getPaymentLocation(final UriInfo uriInfo, final Payment payment) {
-        return uriBuilder.buildLocation(uriInfo, PaymentResource.class, "getPayment", payment.getId(), null);
-    }
-
     private PaymentTransaction findCreatedTransaction(final Payment payment, final TransactionType transactionType, @Nullable final String transactionExternalKey) {
         // Make sure we start looking from the latest transaction created
         final List<PaymentTransaction> reversedTransactions = Lists.reverse(payment.getTransactions());
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 534d07e..a3deec0 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
@@ -107,7 +107,7 @@ public class OverdueResource extends JaxRsResourceBase {
 
         final CallContext callContext = context.createContext(createdBy, reason, comment, request);
         overdueApi.uploadOverdueConfig(overdueXML, callContext);
-        return uriBuilder.buildResponse(uriInfo, OverdueResource.class, null, null);
+        return uriBuilder.buildResponse(uriInfo, OverdueResource.class, null, null, request);
     }
 
     @TimedResource
@@ -140,7 +140,7 @@ public class OverdueResource extends JaxRsResourceBase {
 
         final OverdueConfig overdueConfig = OverdueJson.toOverdueConfigWithValidation(overdueJson);
         overdueApi.uploadOverdueConfig(overdueConfig, callContext);
-        return uriBuilder.buildResponse(uriInfo, OverdueResource.class, null, null);
+        return uriBuilder.buildResponse(uriInfo, OverdueResource.class, null, null, request);
     }
 
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentMethodResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentMethodResource.java
index a5b528b..22e7533 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentMethodResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentMethodResource.java
@@ -303,7 +303,7 @@ public class PaymentMethodResource extends JaxRsResourceBase {
                                        @javax.ws.rs.core.Context final HttpServletRequest request,
                                        @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(UUID.fromString(paymentMethodId), customFields,
-                                        context.createContext(createdBy, reason, comment, request), uriInfo);
+                                        context.createContext(createdBy, reason, comment, request), uriInfo, request);
     }
 
     @TimedResource
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
index 653adb8..8fc205b 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
@@ -323,7 +323,7 @@ public class PaymentResource extends ComboPaymentResource {
                                                                                                  json != null ? json.getTransactionType() : null);
         // If transaction was already completed, return early (See #626)
         if (pendingOrSuccessTransaction.getTransactionStatus() == TransactionStatus.SUCCESS) {
-            return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", pendingOrSuccessTransaction.getPaymentId());
+            return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", pendingOrSuccessTransaction.getPaymentId(), request);
         }
 
 
@@ -357,7 +357,7 @@ public class PaymentResource extends ComboPaymentResource {
             default:
                 return Response.status(Status.PRECONDITION_FAILED).entity("TransactionType " + pendingTransaction.getTransactionType() + " cannot be completed").build();
         }
-        return createPaymentResponse(uriInfo, result, pendingTransaction.getTransactionType(), pendingTransaction.getExternalKey());
+        return createPaymentResponse(uriInfo, result, pendingTransaction.getTransactionType(), pendingTransaction.getExternalKey(), request);
     }
 
     @TimedResource(name = "captureAuthorization")
@@ -433,7 +433,7 @@ public class PaymentResource extends ComboPaymentResource {
 
         final Payment payment = paymentApi.createCaptureWithPaymentControl(account, initialPayment.getId(), json.getAmount(), currency,
                                                          json.getTransactionExternalKey(), pluginProperties, paymentOptions, callContext);
-        return createPaymentResponse(uriInfo, payment, TransactionType.CAPTURE, json.getTransactionExternalKey());
+        return createPaymentResponse(uriInfo, payment, TransactionType.CAPTURE, json.getTransactionExternalKey(), request);
     }
 
     @TimedResource(name = "refundPayment")
@@ -512,7 +512,7 @@ public class PaymentResource extends ComboPaymentResource {
         final Payment payment = paymentApi.createRefundWithPaymentControl(account, initialPayment.getId(), json.getAmount(), currency,
                                                         json.getTransactionExternalKey(), pluginProperties, paymentOptions, callContext);
 
-        return createPaymentResponse(uriInfo, payment, TransactionType.REFUND, json.getTransactionExternalKey());
+        return createPaymentResponse(uriInfo, payment, TransactionType.REFUND, json.getTransactionExternalKey(), request);
     }
 
     @TimedResource(name = "voidPayment")
@@ -584,7 +584,7 @@ public class PaymentResource extends ComboPaymentResource {
 
         final Payment payment = paymentApi.createVoidWithPaymentControl(account, initialPayment.getId(), transactionExternalKey,
                                                                         pluginProperties, paymentOptions, callContext);
-        return createPaymentResponse(uriInfo, payment, TransactionType.VOID, json.getTransactionExternalKey());
+        return createPaymentResponse(uriInfo, payment, TransactionType.VOID, json.getTransactionExternalKey(), request);
     }
 
     @TimedResource(name = "chargebackPayment")
@@ -660,7 +660,7 @@ public class PaymentResource extends ComboPaymentResource {
 
         final Payment payment = paymentApi.createChargebackWithPaymentControl(account, initialPayment.getId(), json.getAmount(), currency,
                                                             json.getTransactionExternalKey(), paymentOptions, callContext);
-        return createPaymentResponse(uriInfo, payment, TransactionType.CHARGEBACK, json.getTransactionExternalKey());
+        return createPaymentResponse(uriInfo, payment, TransactionType.CHARGEBACK, json.getTransactionExternalKey(), request);
     }
 
     @TimedResource(name = "chargebackReversalPayment")
@@ -734,7 +734,7 @@ public class PaymentResource extends ComboPaymentResource {
         final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
 
         final Payment payment = paymentApi.createChargebackReversalWithPaymentControl(account, initialPayment.getId(), json.getTransactionExternalKey(), paymentOptions, callContext);
-        return createPaymentResponse(uriInfo, payment, TransactionType.CHARGEBACK, json.getTransactionExternalKey());
+        return createPaymentResponse(uriInfo, payment, TransactionType.CHARGEBACK, json.getTransactionExternalKey(), request);
     }
 
     @TimedResource
@@ -794,7 +794,7 @@ public class PaymentResource extends ComboPaymentResource {
             default:
                 return Response.status(Status.PRECONDITION_FAILED).entity("TransactionType " + transactionType + " is not allowed for an account").build();
         }
-        return createPaymentResponse(uriInfo, result, transactionType, paymentTransactionJson.getTransactionExternalKey());
+        return createPaymentResponse(uriInfo, result, transactionType, paymentTransactionJson.getTransactionExternalKey(), request);
     }
 
     @TimedResource(name = "cancelScheduledPaymentTransaction")
@@ -863,7 +863,7 @@ public class PaymentResource extends ComboPaymentResource {
                                        @javax.ws.rs.core.Context final HttpServletRequest request,
                                        @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(UUID.fromString(id), customFields,
-                                        context.createContext(createdBy, reason, comment, request), uriInfo);
+                                        context.createContext(createdBy, reason, comment, request), uriInfo, request);
     }
 
     @TimedResource
@@ -915,7 +915,7 @@ public class PaymentResource extends ComboPaymentResource {
                                @javax.ws.rs.core.Context final UriInfo uriInfo,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(UUID.fromString(id), tagList, uriInfo,
-                                context.createContext(createdBy, reason, comment, request));
+                                context.createContext(createdBy, reason, comment, request), request);
     }
 
     @TimedResource
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
index 6cd4f7c..0024c21 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
@@ -240,7 +240,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
 
             @Override
             public Response doResponseOk(final Entitlement createdEntitlement) {
-                return uriBuilder.buildResponse(uriInfo, SubscriptionResource.class, "getEntitlement", createdEntitlement.getId());
+                return uriBuilder.buildResponse(uriInfo, SubscriptionResource.class, "getEntitlement", createdEntitlement.getId(), request);
             }
         };
 
@@ -326,7 +326,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
             }
             @Override
             public Response doResponseOk(final List<Entitlement> entitlements) {
-                return uriBuilder.buildResponse(uriInfo, BundleResource.class, "getBundle", entitlements.get(0).getBundleId());
+                return uriBuilder.buildResponse(uriInfo, BundleResource.class, "getBundle", entitlements.get(0).getBundleId(), request);
             }
         };
         final EntitlementCallCompletion<List<Entitlement>> callCompletionCreation = new EntitlementCallCompletion<List<Entitlement>>();
@@ -416,7 +416,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
             }
             @Override
             public Response doResponseOk(final List<Entitlement> entitlements) {
-                return uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccountBundles", entitlements.get(0).getAccountId(), buildQueryParams(buildBundleIdList(entitlements)));
+                return uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccountBundles", entitlements.get(0).getAccountId(), buildQueryParams(buildBundleIdList(entitlements)), request);
             }
         };
         final EntitlementCallCompletion<List<Entitlement>> callCompletionCreation = new EntitlementCallCompletion<List<Entitlement>>();
@@ -849,7 +849,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
                                        @javax.ws.rs.core.Context final HttpServletRequest request,
                                        @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(UUID.fromString(id), customFields,
-                                        context.createContext(createdBy, reason, comment, request), uriInfo);
+                                        context.createContext(createdBy, reason, comment, request), uriInfo, request);
     }
 
     @DELETE
@@ -899,7 +899,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
                                @javax.ws.rs.core.Context final UriInfo uriInfo,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(UUID.fromString(id), tagList, uriInfo,
-                                context.createContext(createdBy, reason, comment, request));
+                                context.createContext(createdBy, reason, comment, request), request);
     }
 
     @DELETE
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagDefinitionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagDefinitionResource.java
index 8e30db8..90e9b8e 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagDefinitionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TagDefinitionResource.java
@@ -131,7 +131,7 @@ public class TagDefinitionResource extends JaxRsResourceBase {
                              json.getDescription(), "TagDefinition description needs to be set");
 
         final TagDefinition createdTagDef = tagUserApi.createTagDefinition(json.getName(), json.getDescription(), context.createContext(createdBy, reason, comment, request));
-        return uriBuilder.buildResponse(uriInfo, TagDefinitionResource.class, "getTagDefinition", createdTagDef.getId());
+        return uriBuilder.buildResponse(uriInfo, TagDefinitionResource.class, "getTagDefinition", createdTagDef.getId(), request);
     }
 
     @TimedResource
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java
index d348596..e3cbaa2 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TenantResource.java
@@ -142,7 +142,7 @@ public class TenantResource extends JaxRsResourceBase {
                                                                    UserType.CUSTOMER, Context.getOrCreateUserToken(), clock);
             catalogUserApi.createDefaultEmptyCatalog(clock.getUTCNow(),callContext);
         }
-        return uriBuilder.buildResponse(uriInfo, TenantResource.class, "getTenant", tenant.getId());
+        return uriBuilder.buildResponse(uriInfo, TenantResource.class, "getTenant", tenant.getId(), request);
     }
 
     @TimedResource
@@ -341,7 +341,7 @@ public class TenantResource extends JaxRsResourceBase {
                                @javax.ws.rs.core.Context  final UriInfo uriInfo) throws TenantApiException {
         final CallContext callContext = context.createContext(createdBy, reason, comment, request);
         tenantApi.addTenantKeyValue(key, value, callContext);
-        return uriBuilder.buildResponse(uriInfo, TenantResource.class, "getUserKeyValue", key);
+        return uriBuilder.buildResponse(uriInfo, TenantResource.class, "getUserKeyValue", key, request);
     }
 
     @TimedResource
@@ -389,7 +389,7 @@ public class TenantResource extends JaxRsResourceBase {
         final String tenantKey = keyPostfix != null ? key.toString() + keyPostfix : key.toString();
         tenantApi.addTenantKeyValue(tenantKey, value, callContext);
 
-        return uriBuilder.buildResponse(uriInfo, TenantResource.class, getMethodStr, keyPostfix);
+        return uriBuilder.buildResponse(uriInfo, TenantResource.class, getMethodStr, keyPostfix, request);
     }
 
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TransactionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TransactionResource.java
index 1fe9878..38877df 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TransactionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/TransactionResource.java
@@ -47,7 +47,6 @@ import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
 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.PaymentTransaction;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.api.TransactionStatus;
 import org.killbill.billing.util.api.AuditUserApi;
@@ -114,7 +113,7 @@ public class TransactionResource extends JaxRsResourceBase {
 
         final boolean success = TransactionStatus.SUCCESS.name().equals(json.getStatus());
         final Payment result = paymentApi.notifyPendingTransactionOfStateChanged(account, UUID.fromString(transactionIdStr), success, callContext);
-        return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", result.getId());
+        return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", result.getId(), request);
     }
 
 
@@ -145,7 +144,7 @@ public class TransactionResource extends JaxRsResourceBase {
                                        @javax.ws.rs.core.Context final HttpServletRequest request,
                                        @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
         return super.createCustomFields(UUID.fromString(id), customFields,
-                                        context.createContext(createdBy, reason, comment, request), uriInfo);
+                                        context.createContext(createdBy, reason, comment, request), uriInfo, request);
     }
 
     @TimedResource
@@ -196,7 +195,7 @@ public class TransactionResource extends JaxRsResourceBase {
                                @javax.ws.rs.core.Context final UriInfo uriInfo,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
         return super.createTags(UUID.fromString(id), tagList, uriInfo,
-                                context.createContext(createdBy, reason, comment, request));
+                                context.createContext(createdBy, reason, comment, request), request);
     }
 
     @TimedResource
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
index 23d28b4..b0f210e 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/util/JaxrsUriBuilder.java
@@ -22,8 +22,10 @@ import java.util.Map;
 
 import javax.annotation.Nullable;
 import javax.inject.Inject;
+import javax.servlet.ServletRequest;
 import javax.ws.rs.Path;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 
@@ -31,6 +33,8 @@ import org.killbill.billing.jaxrs.resources.JaxRsResourceBase;
 import org.killbill.billing.jaxrs.resources.JaxrsResource;
 import org.killbill.billing.util.config.definition.JaxrsConfig;
 
+import com.google.common.base.MoreObjects;
+
 public class JaxrsUriBuilder {
 
     private final JaxrsConfig jaxrsConfig;
@@ -44,24 +48,51 @@ public class JaxrsUriBuilder {
         this.jaxrsConfig = jaxrsConfig;
     }
 
-    public Response buildResponse(final UriInfo uriInfo, final Class<? extends JaxrsResource> theClass,
-                                  final String getMethodName, final Object objectId) {
-        final URI location = buildLocation(uriInfo, theClass, getMethodName, objectId, null);
-        return !jaxrsConfig.isJaxrsLocationFullUrl() ?
-               Response.status(Response.Status.CREATED).header("Location", location.getPath()).build() :
-               Response.created(location).build();
+    public Response buildResponse(final UriInfo uriInfo,
+                                  final Class<? extends JaxrsResource> theClass,
+                                  final String getMethodName,
+                                  final Object objectId,
+                                  final ServletRequest request) {
+        return buildResponse(uriInfo, theClass, getMethodName, objectId, null, request);
+    }
+
+    public Response buildResponse(final UriInfo uriInfo,
+                                  final Class<? extends JaxrsResource> theClass,
+                                  final String getMethodName,
+                                  final Object objectId,
+                                  final Map<String, String> params,
+                                  final ServletRequest request) {
+        return buildResponse(Response.status(Response.Status.CREATED), uriInfo, theClass, getMethodName, objectId, params, request);
+    }
+
+    public Response buildResponse(final ResponseBuilder responseBuilder,
+                                  final UriInfo uriInfo,
+                                  final Class<? extends JaxrsResource> theClass,
+                                  final String getMethodName,
+                                  final Object objectId,
+                                  final ServletRequest request) {
+        return buildResponse(responseBuilder, uriInfo, theClass, getMethodName, objectId, null, request);
     }
 
-    public Response buildResponse(final UriInfo uriInfo, final Class<? extends JaxrsResource> theClass,
-                                  final String getMethodName, final Object objectId, final Map<String, String> params) {
-        final URI location = buildLocation(uriInfo, theClass, getMethodName, objectId, params);
+    public Response buildResponse(final ResponseBuilder responseBuilder,
+                                  final UriInfo uriInfo,
+                                  final Class<? extends JaxrsResource> theClass,
+                                  final String getMethodName,
+                                  final Object objectId,
+                                  final Map<String, String> params,
+                                  final ServletRequest request) {
+        final URI location = buildLocation(uriInfo, theClass, getMethodName, objectId, params, request);
         return !jaxrsConfig.isJaxrsLocationFullUrl() ?
-               Response.status(Response.Status.CREATED).header("Location", location.getPath()).build() :
-               Response.created(location).build();
+               responseBuilder.header("Location", location.getPath()).build() :
+               responseBuilder.location(location).build();
     }
 
-    public URI buildLocation(final UriInfo uriInfo, final Class<? extends JaxrsResource> theClass,
-                             final String getMethodName, final Object objectId, final Map<String, String> params) {
+    private URI buildLocation(final UriInfo uriInfo,
+                              final Class<? extends JaxrsResource> theClass,
+                              final String getMethodName,
+                              final Object objectId,
+                              final Map<String, String> params,
+                              final ServletRequest request) {
         final UriBuilder uriBuilder = getUriBuilder(uriInfo.getBaseUri().getPath(), theClass, getMethodName);
 
         if (null != params && !params.isEmpty()) {
@@ -71,9 +102,17 @@ public class JaxrsUriBuilder {
         }
 
         if (jaxrsConfig.isJaxrsLocationFullUrl()) {
-            uriBuilder.scheme(uriInfo.getAbsolutePath().getScheme())
-                      .host(uriInfo.getAbsolutePath().getHost())
-                      .port(uriInfo.getAbsolutePath().getPort());
+            if (jaxrsConfig.isJaxrsLocationUseForwardHeaders()) {
+                // Use "remote" value to support X-Forwarded headers (assumes RemoteIpValve or similar is configured)
+                // See https://github.com/killbill/killbill/issues/566
+                uriBuilder.scheme(request.getScheme())
+                          .host(MoreObjects.firstNonNull(jaxrsConfig.getJaxrsLocationHost(), uriInfo.getAbsolutePath().getHost())) // Should we look for X-Forwarded-By instead?
+                          .port(request.getServerPort());
+            } else {
+                uriBuilder.scheme(uriInfo.getAbsolutePath().getScheme())
+                          .host(uriInfo.getAbsolutePath().getHost())
+                          .port(uriInfo.getAbsolutePath().getPort());
+            }
         }
         return objectId != null ? uriBuilder.build(objectId) : uriBuilder.build();
     }
@@ -92,23 +131,6 @@ public class JaxrsUriBuilder {
         return uriBuilder.build();
     }
 
-    public Response buildResponse(final Class<? extends JaxrsResource> theClass, final String getMethodName, final Object objectId, final String baseUri) {
-
-        // Let's build a n absolute location for cross resources
-        // See Jersey ContainerResponse.setHeaders
-        final StringBuilder tmp = new StringBuilder(baseUri.substring(0, baseUri.length() - 1));
-        tmp.append(getUriBuilder(theClass, getMethodName).build(objectId).toString());
-        final URI newUriFromResource = UriBuilder.fromUri(tmp.toString()).build();
-        final Response.ResponseBuilder ri = Response.created(newUriFromResource);
-        final Object obj = new Object() {
-            @SuppressWarnings(value = "all")
-            public URI getUri() {
-                return newUriFromResource;
-            }
-        };
-        return ri.entity(obj).build();
-    }
-
     private UriBuilder getUriBuilder(final String path, final Class<? extends JaxrsResource> theClassMaybeEnhanced, @Nullable final String getMethodName) {
         final Class theClass = getNonEnhancedClass(theClassMaybeEnhanced);
         return getMethodName != null ? fromPath(path.equals("/") ? path.substring(1) : path, theClass, getMethodName) : fromPath(path, theClass);
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBuildResponse.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBuildResponse.java
index 1b54361..c7c622d 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBuildResponse.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBuildResponse.java
@@ -16,23 +16,24 @@
 
 package org.killbill.billing.jaxrs;
 
+import java.net.URI;
+import java.util.UUID;
+
+import javax.servlet.ServletRequest;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
 import org.killbill.billing.jaxrs.resources.AccountResource;
 import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
 import org.killbill.billing.server.log.ServerTestSuiteNoDB;
 import org.killbill.billing.util.config.definition.JaxrsConfig;
 import org.testng.annotations.Test;
 
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import java.net.URI;
-import java.util.UUID;
-
 import com.sun.jersey.api.client.ClientResponse.Status;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertEqualsNoOrder;
 
 public class TestBuildResponse extends ServerTestSuiteNoDB {
 
@@ -47,7 +48,7 @@ public class TestBuildResponse extends ServerTestSuiteNoDB {
         JaxrsConfig jaxrsConfig = mock(JaxrsConfig.class);
         when(jaxrsConfig.isJaxrsLocationFullUrl()).thenReturn(false);
         JaxrsUriBuilder uriBuilder = new JaxrsUriBuilder(jaxrsConfig);
-        Response response = uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccount", objectId);
+        Response response = uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccount", objectId, mockRequest(uriInfo));
 
         assertEquals(response.getStatus(), Status.CREATED.getStatusCode());
         assertEquals(response.getMetadata().get("Location").get(0), "/1.0/kb/accounts/" + objectId.toString());
@@ -64,7 +65,7 @@ public class TestBuildResponse extends ServerTestSuiteNoDB {
         JaxrsConfig jaxrsConfig = mock(JaxrsConfig.class);
         when(jaxrsConfig.isJaxrsLocationFullUrl()).thenReturn(false);
         JaxrsUriBuilder uriBuilder = new JaxrsUriBuilder(jaxrsConfig);
-        Response response = uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccount", objectId);
+        Response response = uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccount", objectId, mockRequest(uriInfo));
 
         assertEquals(response.getStatus(), Status.CREATED.getStatusCode());
         assertEquals(response.getMetadata().get("Location").get(0), "/killbill/1.0/kb/accounts/" + objectId.toString());
@@ -82,7 +83,7 @@ public class TestBuildResponse extends ServerTestSuiteNoDB {
         JaxrsConfig jaxrsConfig = mock(JaxrsConfig.class);
         when(jaxrsConfig.isJaxrsLocationFullUrl()).thenReturn(true);
         JaxrsUriBuilder uriBuilder = new JaxrsUriBuilder(jaxrsConfig);
-        Response response = uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccount", objectId);
+        Response response = uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccount", objectId, mockRequest(uriInfo));
 
         assertEquals(response.getStatus(), Status.CREATED.getStatusCode());
         assertEquals(response.getMetadata().get("Location").get(0).toString(), uri.toString() + "/1.0/kb/accounts/" + objectId.toString());
@@ -100,9 +101,21 @@ public class TestBuildResponse extends ServerTestSuiteNoDB {
         JaxrsConfig jaxrsConfig = mock(JaxrsConfig.class);
         when(jaxrsConfig.isJaxrsLocationFullUrl()).thenReturn(true);
         JaxrsUriBuilder uriBuilder = new JaxrsUriBuilder(jaxrsConfig);
-        Response response = uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccount", objectId);
+        Response response = uriBuilder.buildResponse(uriInfo, AccountResource.class, "getAccount", objectId, mockRequest(uriInfo));
 
         assertEquals(response.getStatus(), Status.CREATED.getStatusCode());
         assertEquals(response.getMetadata().get("Location").get(0).toString(), uri.toString() + "/1.0/kb/accounts/" + objectId.toString());
     }
+
+    private ServletRequest mockRequest(final UriInfo uriInfo) throws Exception {
+        final ServletRequest request = mock(ServletRequest.class);
+        final URI absolutePath = uriInfo.getAbsolutePath();
+        if (absolutePath != null) {
+            final String scheme = absolutePath.getScheme();
+            when(request.getScheme()).thenReturn(scheme);
+            final int port = absolutePath.getPort();
+            when(request.getServerPort()).thenReturn(port);
+        }
+        return request;
+    }
 }
diff --git a/util/src/main/java/org/killbill/billing/util/config/definition/JaxrsConfig.java b/util/src/main/java/org/killbill/billing/util/config/definition/JaxrsConfig.java
index 95fe22d..ba941a2 100644
--- a/util/src/main/java/org/killbill/billing/util/config/definition/JaxrsConfig.java
+++ b/util/src/main/java/org/killbill/billing/util/config/definition/JaxrsConfig.java
@@ -19,6 +19,7 @@ package org.killbill.billing.util.config.definition;
 
 import org.skife.config.Config;
 import org.skife.config.Default;
+import org.skife.config.DefaultNull;
 import org.skife.config.Description;
 import org.skife.config.TimeSpan;
 
@@ -39,4 +40,13 @@ public interface JaxrsConfig extends KillbillConfig {
     @Description("Type of return for the jaxrs response location URL")
     boolean isJaxrsLocationFullUrl();
 
+    @Config("org.killbill.jaxrs.location.useForwardHeaders")
+    @Default("true")
+    @Description("Whether to respect X-Forwarded headers for redirect URLs")
+    boolean isJaxrsLocationUseForwardHeaders();
+
+    @Config("org.killbill.jaxrs.location.host")
+    @DefaultNull
+    @Description("Base host address to use for redirect URLs")
+    String getJaxrsLocationHost();
 }