killbill-memoizeit

Changes

account/pom.xml 2(+1 -1)

api/pom.xml 2(+1 -1)

beatrix/pom.xml 2(+1 -1)

catalog/pom.xml 2(+1 -1)

currency/pom.xml 2(+1 -1)

invoice/pom.xml 2(+1 -1)

jaxrs/pom.xml 2(+1 -1)

junction/pom.xml 2(+1 -1)

NEWS 3(+3 -0)

overdue/pom.xml 2(+1 -1)

payment/pom.xml 2(+1 -1)

pom.xml 2(+1 -1)

profiles/pom.xml 2(+1 -1)

tenant/pom.xml 2(+1 -1)

usage/pom.xml 2(+1 -1)

util/pom.xml 2(+1 -1)

Details

account/pom.xml 2(+1 -1)

diff --git a/account/pom.xml b/account/pom.xml
index 487e17e..df1ec85 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-account</artifactId>

api/pom.xml 2(+1 -1)

diff --git a/api/pom.xml b/api/pom.xml
index b9519bd..0435593 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-internal-api</artifactId>

beatrix/pom.xml 2(+1 -1)

diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index d984e71..689180a 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-beatrix</artifactId>

catalog/pom.xml 2(+1 -1)

diff --git a/catalog/pom.xml b/catalog/pom.xml
index 671a175..3a28cf4 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-catalog</artifactId>

currency/pom.xml 2(+1 -1)

diff --git a/currency/pom.xml b/currency/pom.xml
index e2ec193..fc2b5a7 100644
--- a/currency/pom.xml
+++ b/currency/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-currency</artifactId>
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index e3f2c05..02d02a8 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-entitlement</artifactId>

invoice/pom.xml 2(+1 -1)

diff --git a/invoice/pom.xml b/invoice/pom.xml
index bb1cf1f..ec47467 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-invoice</artifactId>

jaxrs/pom.xml 2(+1 -1)

diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index 6370260..4fc64e3 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-jaxrs</artifactId>
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 6f8e466..c988902 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
@@ -99,6 +99,7 @@ import org.killbill.billing.payment.api.PaymentMethod;
 import org.killbill.billing.payment.api.PaymentOptions;
 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.AuditLevel;
@@ -949,10 +950,15 @@ public class AccountResource extends JaxRsResourceBase {
         final UUID paymentMethodId;
         if (paymentId != null) {
             final Payment initialPayment = paymentApi.getPayment(paymentId, false, false, pluginProperties, callContext);
-            final PaymentTransaction pendingTransaction = lookupPendingTransaction(initialPayment,
+            final PaymentTransaction pendingOrSuccessTransaction = lookupPendingOrSuccessTransaction(initialPayment,
                                                                                    json != null ? json.getTransactionId() : null,
                                                                                    json != null ? json.getTransactionExternalKey() : null,
                                                                                    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());
+            }
+
             paymentMethodId = initialPayment.getPaymentMethodId();
         } else {
             paymentMethodId = paymentMethodIdStr == null ? account.getPaymentMethodId() : UUID.fromString(paymentMethodIdStr);
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 1dbc78b..ce30ab9 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
@@ -348,11 +348,11 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         }
     }
 
-    protected PaymentTransaction lookupPendingTransaction(final Payment initialPayment, @Nullable final String transactionId, @Nullable final String transactionExternalKey, @Nullable final String transactionType) throws PaymentApiException {
+    protected PaymentTransaction lookupPendingOrSuccessTransaction(final Payment initialPayment, @Nullable final String transactionId, @Nullable final String transactionExternalKey, @Nullable final String transactionType) throws PaymentApiException {
         final Collection<PaymentTransaction> pendingTransaction  =  Collections2.filter(initialPayment.getTransactions(), new Predicate<PaymentTransaction>() {
             @Override
             public boolean apply(final PaymentTransaction input) {
-                if (input.getTransactionStatus() != TransactionStatus.PENDING) {
+                if (input.getTransactionStatus() != TransactionStatus.PENDING && input.getTransactionStatus() != TransactionStatus.SUCCESS) {
                     return false;
                 }
                 if (transactionId != null && !transactionId.equals(input.getId().toString())) {
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 e0e13b8..653adb8 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
@@ -61,6 +61,7 @@ import org.killbill.billing.payment.api.PaymentApiException;
 import org.killbill.billing.payment.api.PaymentOptions;
 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.api.AuditUserApi;
 import org.killbill.billing.util.api.CustomFieldApiException;
@@ -80,6 +81,7 @@ import com.google.common.base.Function;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
@@ -302,7 +304,12 @@ public class PaymentResource extends ComboPaymentResource {
                                                  final UriInfo uriInfo,
                                                  final HttpServletRequest request) throws PaymentApiException, AccountApiException {
 
-        final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
+        final Iterable<PluginProperty> pluginPropertiesFromBody = extractPluginProperties(json.getProperties());
+
+        final Iterable<PluginProperty> pluginPropertiesFromQuery = extractPluginProperties(pluginPropertiesString);
+
+        final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
+
         final CallContext callContext = context.createContext(createdBy, reason, comment, request);
         final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json == null ? null : json.getPaymentExternalKey(), pluginProperties, callContext);
 
@@ -310,11 +317,17 @@ public class PaymentResource extends ComboPaymentResource {
         final BigDecimal amount = json == null ? null : json.getAmount();
         final Currency currency = json == null || json.getCurrency() == null ? null : Currency.valueOf(json.getCurrency());
 
-            final PaymentTransaction pendingTransaction = lookupPendingTransaction(initialPayment,
-                                                                                   json != null ? json.getTransactionId() : null,
-                                                                                   json != null ? json.getTransactionExternalKey() : null,
-                                                                                   json != null ? json.getTransactionType() : null);
+        final PaymentTransaction pendingOrSuccessTransaction = lookupPendingOrSuccessTransaction(initialPayment,
+                                                                                                 json != null ? json.getTransactionId() : null,
+                                                                                                 json != null ? json.getTransactionExternalKey() : null,
+                                                                                                 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());
+        }
+
 
+        final PaymentTransaction pendingTransaction = pendingOrSuccessTransaction;
         final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
         final Payment result;
         switch (pendingTransaction.getTransactionType()) {

junction/pom.xml 2(+1 -1)

diff --git a/junction/pom.xml b/junction/pom.xml
index b66ae80..8e003a7 100644
--- a/junction/pom.xml
+++ b/junction/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-junction</artifactId>

NEWS 3(+3 -0)

diff --git a/NEWS b/NEWS
index f2fd8ff..8bc0c7b 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,6 @@
+0.17.6
+    See https://github.com/killbill/killbill/releases/tag/killbill-0.17.6
+
 0.17.5
     See https://github.com/killbill/killbill/releases/tag/killbill-0.17.5
 

overdue/pom.xml 2(+1 -1)

diff --git a/overdue/pom.xml b/overdue/pom.xml
index c33e0d2..31afc8d 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-overdue</artifactId>

payment/pom.xml 2(+1 -1)

diff --git a/payment/pom.xml b/payment/pom.xml
index fa92810..29c1b08 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-payment</artifactId>

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index 250ee1d..8884d34 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
         <version>0.134-SNAPSHOT</version>
     </parent>
     <artifactId>killbill</artifactId>
-    <version>0.17.6-SNAPSHOT</version>
+    <version>0.17.7-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>killbill</name>
     <description>Library for managing recurring subscriptions and the associated billing</description>
diff --git a/profiles/killbill/pom.xml b/profiles/killbill/pom.xml
index 4bee84c..2f15884 100644
--- a/profiles/killbill/pom.xml
+++ b/profiles/killbill/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill-profiles</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-profiles-killbill</artifactId>
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/LuhnMaskingObfuscator.java b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/LuhnMaskingObfuscator.java
index 1edb705..8ad5478 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/LuhnMaskingObfuscator.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/LuhnMaskingObfuscator.java
@@ -76,10 +76,7 @@ public class LuhnMaskingObfuscator extends Obfuscator {
                 numberEnd = last4pos[3] + 1;
                 if ((digitsSeen >= MIN_CC_DIGITS)
                     && luhnCheck(stripSeparators(formattedMessage.substring(numberStart, numberEnd)))) {
-                    masked.append(formattedMessage, unwrittenStart, numberStart);
-                    masked.append(obfuscateConfidentialData(formattedMessage.substring(numberStart, numberEnd),
-                                                            formattedMessage.substring(last4pos[0], numberEnd)));
-                    masked.append(formattedMessage, last4pos[0], numberEnd);
+                    maskCC(formattedMessage, unwrittenStart, numberStart, numberEnd, last4pos[0], masked);
                     unwrittenStart = numberEnd;
                 }
                 numberStart = -1;
@@ -89,10 +86,7 @@ public class LuhnMaskingObfuscator extends Obfuscator {
 
         if (numberStart != -1 && (digitsSeen >= MIN_CC_DIGITS)
             && luhnCheck(stripSeparators(formattedMessage.substring(numberStart, pos)))) {
-            masked.append(formattedMessage, unwrittenStart, numberStart);
-            masked.append(obfuscateConfidentialData(formattedMessage.substring(numberStart, pos),
-                                                    formattedMessage.substring(last4pos[0], pos)));
-            masked.append(formattedMessage, last4pos[0], pos);
+            maskCC(formattedMessage, unwrittenStart, numberStart, pos, last4pos[0], masked);
         } else {
             masked.append(formattedMessage, unwrittenStart, pos);
         }
@@ -100,6 +94,30 @@ public class LuhnMaskingObfuscator extends Obfuscator {
         return masked.toString();
     }
 
+    private void maskCC(final String formattedMessage, final int unwrittenStart, final int numberStart, final int numberEnd, final int last4pos, final StringBuilder masked) {
+        masked.append(formattedMessage, unwrittenStart, numberStart);
+
+        // Don't mask the BIN
+        int binNumbersLeft = 6;
+        int panStartPos = numberStart;
+        char current;
+        while (binNumbersLeft > 0) {
+            current = formattedMessage.charAt(panStartPos);
+            if (isDigit(current)) {
+                masked.append(current);
+                binNumbersLeft--;
+            }
+            panStartPos++;
+        }
+
+        // Append the mask
+        masked.append(obfuscateConfidentialData(formattedMessage.substring(panStartPos, numberEnd),
+                                                formattedMessage.substring(last4pos, numberEnd)));
+
+        // Append last 4
+        masked.append(formattedMessage, last4pos, numberEnd);
+    }
+
     private boolean hasEnoughDigits(final CharSequence formattedMessage) {
         int digits = 0;
         final int length = formattedMessage.length();
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/Obfuscator.java b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/Obfuscator.java
index bf37cca..cd4426d 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/Obfuscator.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/log/obfuscators/Obfuscator.java
@@ -34,17 +34,7 @@ public abstract class Obfuscator {
 
     protected static final int DEFAULT_PATTERN_FLAGS = Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL;
 
-    protected static final String MASK_LABEL = "MASKED";
-    protected static final int MASK_LABEL_LENGTH = MASK_LABEL.length();
     protected static final char PAD_CHAR = '*';
-    protected static final int MASK_LOOKUPS_SIZE = 20;
-    protected final String[] MASK_LOOKUPS = new String[MASK_LOOKUPS_SIZE];
-
-    public Obfuscator() {
-        for (int i = 0; i < MASK_LOOKUPS.length; i++) {
-            MASK_LOOKUPS[i] = buildMask(i);
-        }
-    }
 
     public abstract String obfuscate(final String originalString, final ILoggingEvent event);
 
@@ -111,33 +101,6 @@ public abstract class Obfuscator {
     @VisibleForTesting
     String obfuscateConfidentialData(final CharSequence confidentialSequence, @Nullable final CharSequence unmasked) {
         final int maskedLength = unmasked == null ? confidentialSequence.length() : confidentialSequence.length() - unmasked.length();
-        if (maskedLength < MASK_LOOKUPS_SIZE) {
-            return MASK_LOOKUPS[maskedLength];
-        } else {
-            return buildMask(maskedLength);
-        }
-    }
-
-    /**
-     * Create a masking string with the given length.
-     *
-     * @param maskedLength obfuscated String length
-     * @return a mask string
-     */
-    private String buildMask(final int maskedLength) {
-        final int pads = maskedLength - MASK_LABEL_LENGTH;
-        final StringBuilder mask = new StringBuilder(maskedLength);
-        if (pads <= 0) {
-            mask.append(MASK_LABEL);
-        } else {
-            for (int i = 0; i < pads / 2; i++) {
-                mask.append(PAD_CHAR);
-            }
-            mask.append(MASK_LABEL);
-            while (mask.length() < maskedLength) {
-                mask.append(PAD_CHAR);
-            }
-        }
-        return mask.toString();
+        return new String(new char[maskedLength]).replace('\0', PAD_CHAR);
     }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
index 928ba11..88cb7ea 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
@@ -505,15 +505,10 @@ public class TestPayment extends TestJaxrsBase {
 
         final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, TransactionStatus.SUCCESS.name(), amount, amount, pluginProperties, 1);
 
-        // The payment was already completed
+        // The payment was already completed, it should succeed (no-op)
         final PaymentTransaction completeTransactionByPaymentId = new PaymentTransaction();
         completeTransactionByPaymentId.setPaymentId(initialPayment.getPaymentId());
-        try {
-            killBillClient.completePayment(completeTransactionByPaymentId, pluginProperties, basicRequestOptions());
-            fail("Completion should not succeed, there is no PENDING payment transaction");
-        } catch (final KillBillClientException expected) {
-            // Invalid parameter paymentId: XXXX
-        }
+        killBillClient.completePayment(completeTransactionByPaymentId, pluginProperties, basicRequestOptions());
     }
 
 
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentPluginProperties.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentPluginProperties.java
new file mode 100644
index 0000000..e24c9a9
--- /dev/null
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPaymentPluginProperties.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 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.jaxrs;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.killbill.billing.client.KillBillClientException;
+import org.killbill.billing.client.KillBillHttpClient;
+import org.killbill.billing.client.RequestOptions;
+import org.killbill.billing.client.model.Account;
+import org.killbill.billing.client.model.Payment;
+import org.killbill.billing.client.model.PaymentTransaction;
+import org.killbill.billing.client.model.PluginProperty;
+import org.killbill.billing.control.plugin.api.OnFailurePaymentControlResult;
+import org.killbill.billing.control.plugin.api.OnSuccessPaymentControlResult;
+import org.killbill.billing.control.plugin.api.PaymentControlApiException;
+import org.killbill.billing.control.plugin.api.PaymentControlContext;
+import org.killbill.billing.control.plugin.api.PaymentControlPluginApi;
+import org.killbill.billing.control.plugin.api.PriorPaymentControlResult;
+import org.killbill.billing.osgi.api.OSGIServiceDescriptor;
+import org.killbill.billing.osgi.api.OSGIServiceRegistration;
+import org.killbill.billing.payment.api.TransactionType;
+import org.killbill.billing.payment.plugin.api.PaymentPluginStatus;
+import org.killbill.billing.payment.provider.MockPaymentProviderPlugin;
+import org.killbill.billing.payment.retry.DefaultFailureCallResult;
+import org.killbill.billing.payment.retry.DefaultOnSuccessPaymentControlResult;
+import org.killbill.billing.payment.retry.DefaultPriorPaymentControlResult;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.Multimap;
+import com.google.inject.Inject;
+
+public class TestPaymentPluginProperties extends TestJaxrsBase {
+
+    @Inject
+    private OSGIServiceRegistration<PaymentControlPluginApi> controlPluginRegistry;
+
+    private PluginPropertiesVerificator mockPaymentControlProviderPlugin;
+
+    public static class PluginPropertiesVerificator implements PaymentControlPluginApi {
+
+        public static final String PLUGIN_NAME = "PLUGIN_PROPERTY_VERIFICATOR";
+
+        private Iterable<org.killbill.billing.payment.api.PluginProperty> expectedProperties;
+
+        public PluginPropertiesVerificator() {
+            clearExpectPluginProperties();
+        }
+
+        @Override
+        public PriorPaymentControlResult priorCall(final PaymentControlContext paymentControlContext, final Iterable<org.killbill.billing.payment.api.PluginProperty> properties) throws PaymentControlApiException {
+            assertPluginProperties(properties);
+            return new DefaultPriorPaymentControlResult(false);
+        }
+
+        @Override
+        public OnSuccessPaymentControlResult onSuccessCall(final PaymentControlContext paymentControlContext, final Iterable<org.killbill.billing.payment.api.PluginProperty> properties) throws PaymentControlApiException {
+            return new DefaultOnSuccessPaymentControlResult();
+        }
+
+        @Override
+        public OnFailurePaymentControlResult onFailureCall(final PaymentControlContext paymentControlContext, final Iterable<org.killbill.billing.payment.api.PluginProperty> properties) throws PaymentControlApiException {
+            return new DefaultFailureCallResult();
+        }
+
+        public void setExpectPluginProperties(final Iterable<org.killbill.billing.payment.api.PluginProperty> expectedProperties) {
+            this.expectedProperties = expectedProperties;
+        }
+
+        public void clearExpectPluginProperties() {
+            this.expectedProperties = ImmutableList.of();
+        }
+
+        private void assertPluginProperties(final Iterable<org.killbill.billing.payment.api.PluginProperty> properties) {
+            for (org.killbill.billing.payment.api.PluginProperty input : properties) {
+                boolean found  = false;
+                for (org.killbill.billing.payment.api.PluginProperty expect : expectedProperties) {
+                    if (expect.getKey().equals(input.getKey()) && expect.getValue().equals(expect.getValue())) {
+                        found = true;
+                        break;
+                    }
+                }
+                Assert.assertTrue(found);
+            }
+
+            for (org.killbill.billing.payment.api.PluginProperty expect : properties) {
+                boolean found  = false;
+                for (org.killbill.billing.payment.api.PluginProperty input : expectedProperties) {
+                    if (expect.getKey().equals(input.getKey()) && expect.getValue().equals(expect.getValue())) {
+                        found = true;
+                        break;
+                    }
+                }
+                Assert.assertTrue(found);
+            }
+        }
+    }
+
+    @BeforeMethod(groups = "slow")
+    public void beforeMethod() throws Exception {
+        super.beforeMethod();
+
+        mockPaymentControlProviderPlugin = new PluginPropertiesVerificator();
+        controlPluginRegistry.registerService(new OSGIServiceDescriptor() {
+            @Override
+            public String getPluginSymbolicName() {
+                return null;
+            }
+
+            @Override
+            public String getPluginName() {
+                return PluginPropertiesVerificator.PLUGIN_NAME;
+            }
+
+            @Override
+            public String getRegistrationName() {
+                return PluginPropertiesVerificator.PLUGIN_NAME;
+            }
+        }, mockPaymentControlProviderPlugin);
+    }
+
+    @AfterMethod(groups = "slow")
+    public void tearDown() throws Exception {
+        mockPaymentControlProviderPlugin.clearExpectPluginProperties();
+    }
+
+    @Test(groups = "slow")
+    public void testWithQueryPropertiesOnly() throws Exception {
+        final List<org.killbill.billing.payment.api.PluginProperty> expectProperties = new ArrayList<org.killbill.billing.payment.api.PluginProperty>();
+
+        final Map<String, String> queryProperties = new HashMap<String, String>();
+        addProperty("key1", "val1", queryProperties, expectProperties);
+        addProperty("key2", "val2", queryProperties, expectProperties);
+        addProperty("key3", "val3", queryProperties, expectProperties);
+        addProperty("key4", "val4", queryProperties, expectProperties);
+
+        final List<PluginProperty> bodyProperties = new ArrayList<PluginProperty>();
+
+        testInternal(queryProperties, bodyProperties, expectProperties);
+
+    }
+
+    @Test(groups = "slow")
+    public void testWithBodyPropertiesOnly() throws Exception {
+        final List<org.killbill.billing.payment.api.PluginProperty> expectProperties = new ArrayList<org.killbill.billing.payment.api.PluginProperty>();
+
+        final Map<String, String> queryProperties = new HashMap<String, String>();
+
+        final List<PluginProperty> bodyProperties = new ArrayList<PluginProperty>();
+        addProperty("keyXXX1", "valXXXX1", bodyProperties, expectProperties);
+        addProperty("keyXXX2", "valXXXX2", bodyProperties, expectProperties);
+        addProperty("keyXXX3", "valXXXX3", bodyProperties, expectProperties);
+
+        testInternal(queryProperties, bodyProperties, expectProperties);
+
+    }
+
+    @Test(groups = "slow")
+    public void testWithBodyAndQueryProperties() throws Exception {
+        final List<org.killbill.billing.payment.api.PluginProperty> expectProperties = new ArrayList<org.killbill.billing.payment.api.PluginProperty>();
+
+        final Map<String, String> queryProperties = new HashMap<String, String>();
+        addProperty("key1", "val1", queryProperties, expectProperties);
+        addProperty("key2", "val2", queryProperties, expectProperties);
+        addProperty("key3", "val3", queryProperties, expectProperties);
+        addProperty("key4", "val4", queryProperties, expectProperties);
+
+        final List<PluginProperty> bodyProperties = new ArrayList<PluginProperty>();
+        addProperty("keyXXX1", "valXXXX1", bodyProperties, expectProperties);
+        addProperty("keyXXX2", "valXXXX2", bodyProperties, expectProperties);
+        addProperty("keyXXX3", "valXXXX3", bodyProperties, expectProperties);
+
+        testInternal(queryProperties, bodyProperties, expectProperties);
+    }
+
+    private void testInternal(final Map<String, String> queryProperties, final List<PluginProperty> bodyProperties, final List<org.killbill.billing.payment.api.PluginProperty> expectProperties) throws Exception {
+        final Account account = createAccountWithDefaultPaymentMethod();
+        final UUID paymentMethodId = account.getPaymentMethodId();
+        final BigDecimal amount = BigDecimal.TEN;
+
+        final String pending = PaymentPluginStatus.PENDING.toString();
+        final ImmutableMap<String, String> pluginProperties = ImmutableMap.<String, String>of(MockPaymentProviderPlugin.PLUGIN_PROPERTY_PAYMENT_PLUGIN_STATUS_OVERRIDE, pending);
+
+        TransactionType transactionType = TransactionType.AUTHORIZE;
+        final String paymentExternalKey = UUID.randomUUID().toString();
+        final String authTransactionExternalKey = UUID.randomUUID().toString();
+
+        final Payment initialPayment = createVerifyTransaction(account, paymentMethodId, paymentExternalKey, authTransactionExternalKey, transactionType, amount, pluginProperties);
+
+        mockPaymentControlProviderPlugin.setExpectPluginProperties(expectProperties);
+
+        // Complete operation: first, only specify the payment id
+        final PaymentTransaction completeTransactionByPaymentId = new PaymentTransaction();
+        completeTransactionByPaymentId.setPaymentId(initialPayment.getPaymentId());
+        completeTransactionByPaymentId.setProperties(bodyProperties);
+
+        final RequestOptions basicRequestOptions = basicRequestOptions();
+        final Multimap<String, String> params = LinkedListMultimap.create(basicRequestOptions.getQueryParams());
+        params.putAll(KillBillHttpClient.CONTROL_PLUGIN_NAME, ImmutableList.<String>of(PluginPropertiesVerificator.PLUGIN_NAME));
+
+        final RequestOptions requestOptionsWithParams = basicRequestOptions.extend()
+                                                          .withQueryParams(params).build();
+
+        killBillClient.completePayment(completeTransactionByPaymentId, queryProperties, requestOptionsWithParams);
+    }
+
+    private Payment createVerifyTransaction(final Account account,
+                                            @Nullable final UUID paymentMethodId,
+                                            final String paymentExternalKey,
+                                            final String transactionExternalKey,
+                                            final TransactionType transactionType,
+                                            final BigDecimal transactionAmount,
+                                            final Map<String, String> pluginProperties) throws KillBillClientException {
+        final PaymentTransaction authTransaction = new PaymentTransaction();
+        authTransaction.setAmount(transactionAmount);
+        authTransaction.setCurrency(account.getCurrency());
+        authTransaction.setPaymentExternalKey(paymentExternalKey);
+        authTransaction.setTransactionExternalKey(transactionExternalKey);
+        authTransaction.setTransactionType(transactionType.toString());
+        final Payment payment = killBillClient.createPayment(account.getAccountId(), paymentMethodId, authTransaction, pluginProperties, basicRequestOptions());
+        return payment;
+    }
+
+    private void addProperty(final String key, final String value, final Map<String, String> dest, final List<org.killbill.billing.payment.api.PluginProperty> expectProperties) {
+        dest.put(key, value);
+        expectProperties.add(new org.killbill.billing.payment.api.PluginProperty(key, value, false));
+    }
+
+    private void addProperty(final String key, final String value, List<PluginProperty> bodyProperties, final List<org.killbill.billing.payment.api.PluginProperty> expectProperties) {
+        bodyProperties.add(new PluginProperty(key, value, false));
+        expectProperties.add(new org.killbill.billing.payment.api.PluginProperty(key, value, false));
+    }
+}
\ No newline at end of file
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestConfigMagicObfuscator.java b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestConfigMagicObfuscator.java
index fb6d67e..51a41c7 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestConfigMagicObfuscator.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestConfigMagicObfuscator.java
@@ -31,19 +31,19 @@ public class TestConfigMagicObfuscator extends ServerTestSuiteNoDB {
     @Test(groups = "fast")
     public void testKey() throws Exception {
         verify("Assigning value [pass2b78b7cef] for [org.killbill.billing.plugin.avatax.licenseKey] on [org.killbill.billing.plugins.avatax#getLicenseKey()]",
-               "Assigning value [***MASKED****] for [org.killbill.billing.plugin.avatax.licenseKey] on [org.killbill.billing.plugins.avatax#getLicenseKey()]");
+               "Assigning value [*************] for [org.killbill.billing.plugin.avatax.licenseKey] on [org.killbill.billing.plugins.avatax#getLicenseKey()]");
 
         verify("Assigning value [pass2b78b7cef] for [org.killbill.billing.plugin.avatax.apiKey] on [org.killbill.billing.plugins.avatax#getApiKey()]",
-               "Assigning value [***MASKED****] for [org.killbill.billing.plugin.avatax.apiKey] on [org.killbill.billing.plugins.avatax#getApiKey()]");
+               "Assigning value [*************] for [org.killbill.billing.plugin.avatax.apiKey] on [org.killbill.billing.plugins.avatax#getApiKey()]");
     }
 
     @Test(groups = "fast")
     public void testPassword() throws Exception {
         verify("Assigning value [pass2b78b7ce] for [org.killbill.dao.pass] on [org.killbill.commons.jdbi.guice.DaoConfig#getPass()]",
-               "Assigning value [***MASKED***] for [org.killbill.dao.pass] on [org.killbill.commons.jdbi.guice.DaoConfig#getPass()]");
+               "Assigning value [************] for [org.killbill.dao.pass] on [org.killbill.commons.jdbi.guice.DaoConfig#getPass()]");
 
         verify("Assigning value [pass2b78b7ce] for [org.killbill.dao.password] on [org.killbill.commons.jdbi.guice.DaoConfig#getPassword()]",
-               "Assigning value [***MASKED***] for [org.killbill.dao.password] on [org.killbill.commons.jdbi.guice.DaoConfig#getPassword()]");
+               "Assigning value [************] for [org.killbill.dao.password] on [org.killbill.commons.jdbi.guice.DaoConfig#getPassword()]");
     }
 
     private void verify(final String input, final String output) {
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestLuhnMaskingObfuscator.java b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestLuhnMaskingObfuscator.java
index 794a96d..29d51ef 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestLuhnMaskingObfuscator.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestLuhnMaskingObfuscator.java
@@ -50,17 +50,17 @@ public class TestLuhnMaskingObfuscator extends ServerTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testConvert() {
-        verify("try 5137 0049 8639 6404 and 5137 0049 8639 6403", "try 5137 0049 8639 6404 and ****MASKED*****6403");
+        verify("try 5137 0049 8639 6404 and 5137 0049 8639 6403", "try 5137 0049 8639 6404 and 513700********6403");
     }
 
     @Test(groups = "fast")
     public void testConvertCcNumberAtStartNonCcNumberAtEnd() {
-        verify("5137 0049 8639 6403 and 5137 0049 8639 6404", "****MASKED*****6403 and 5137 0049 8639 6404");
+        verify("5137 0049 8639 6403 and 5137 0049 8639 6404", "513700********6403 and 5137 0049 8639 6404");
     }
 
     @Test(groups = "fast")
     public void testConvertMultiple() {
-        verify("try 5137 0049 8639 6403 multiple 5137 0049 8639 6404 possible 4111-1111-1111 1111 card 4111111111111112 numbers", "try ****MASKED*****6403 multiple 5137 0049 8639 6404 possible ****MASKED*****1111 card 4111111111111112 numbers");
+        verify("try 5137 0049 8639 6403 multiple 5137 0049 8639 6404 possible 4111-1111-1111 1111 card 4111111111111112 numbers", "try 513700********6403 multiple 5137 0049 8639 6404 possible 411111********1111 card 4111111111111112 numbers");
     }
 
     @Test(groups = "fast")
@@ -102,41 +102,41 @@ public class TestLuhnMaskingObfuscator extends ServerTestSuiteNoDB {
                + "Switch/Solo (Paymentech)"
                + "6331101999990016",
                "American Express"
-               + "**MASKED***0005"
+               + "378282*****0005"
                + "American Express"
-               + "**MASKED***8431"
+               + "371449*****8431"
                + "American Express Corporate"
-               + "**MASKED***1000"
+               + "378734*****1000"
                + "Australian BankCard"
-               + "***MASKED***8250"
+               + "561059******8250"
                + "Diners Club"
-               + "**MASKED**5904"
+               + "305693****5904"
                + "Diners Club"
-               + "**MASKED**3237"
+               + "385200****3237"
                + "Discover"
-               + "***MASKED***1117"
+               + "601111******1117"
                + "Discover"
-               + "***MASKED***9424"
+               + "601100******9424"
                + "JCB"
-               + "***MASKED***0000"
+               + "353011******0000"
                + "JCB"
-               + "***MASKED***0505"
+               + "356600******0505"
                + "MasterCard"
-               + "***MASKED***4444"
+               + "555555******4444"
                + "MasterCard"
-               + "***MASKED***5100"
+               + "510510******5100"
                + "Visa"
-               + "***MASKED***1111"
+               + "411111******1111"
                + "Visa"
-               + "***MASKED***1881"
+               + "401288******1881"
                + "Visa"
-               + "*MASKED**2222"
+               + "422222***2222"
                + "Note : Even though this number has a different character count than the other test numbers, it is the correct and functional number."
                + "Processor-specific Cards"
                + "Dankort (PBS)"
-               + "***MASKED***3742"
+               + "501971******3742"
                + "Switch/Solo (Paymentech)"
-               + "***MASKED***0016");
+               + "633110******0016");
     }
 
     @Test(groups = "fast")
@@ -235,7 +235,7 @@ public class TestLuhnMaskingObfuscator extends ServerTestSuiteNoDB {
                "1 > Content-Type: application/json\n" +
                "1 > Accept: */*",
                "1 * Server in-bound request\n" +
-               "1 > POST http://127.0.0.1:8080/1.0/kb/accounts/2a55045a-ce1d-4344-942d-b825536328f9/payments?pluginProperty=cc_number=***MASKED***1111\n" +
+               "1 > POST http://127.0.0.1:8080/1.0/kb/accounts/2a55045a-ce1d-4344-942d-b825536328f9/payments?pluginProperty=cc_number=411111******1111\n" +
                "1 > X-Killbill-ApiSecret: lazar\n" +
                "1 > Authorization: Basic YWRtaW46cGFzc3dvcmQ=\n" +
                "1 > X-Killbill-CreatedBy: admin\n" +
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscator.java b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscator.java
index 5109ad3..b36c2a5 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscator.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscator.java
@@ -41,7 +41,7 @@ public class TestObfuscator extends ServerTestSuiteNoDB {
         final Pattern pattern = Pattern.compile("number=([^;]+)");
         final ImmutableList<Pattern> patterns = ImmutableList.<Pattern>of(pattern);
         Assert.assertEquals(obfuscator.obfuscate("number=1234;number=12345;number=123456;number=1234567;number=12345678;number=123456789", patterns, Mockito.mock(ILoggingEvent.class)),
-                            "number=MASKED;number=MASKED;number=MASKED;number=MASKED*;number=*MASKED*;number=*MASKED**");
+                            "number=****;number=*****;number=******;number=*******;number=********;number=*********");
 
     }
 
@@ -51,12 +51,12 @@ public class TestObfuscator extends ServerTestSuiteNoDB {
         final Pattern pattern2 = Pattern.compile("numberB=([^;]+)");
         final ImmutableList<Pattern> patterns = ImmutableList.<Pattern>of(pattern1, pattern2);
         Assert.assertEquals(obfuscator.obfuscate("number=1234;numberB=12345;number=123456;numberB=1234567;number=12345678;numberB=123456789", patterns, Mockito.mock(ILoggingEvent.class)),
-                            "number=MASKED;numberB=MASKED;number=MASKED;numberB=MASKED*;number=*MASKED*;numberB=*MASKED**");
+                            "number=****;numberB=*****;number=******;numberB=*******;number=********;numberB=*********");
 
     }
 
     @Test(groups = "fast")
     public void testObfuscateConfidentialData() {
-        Assert.assertEquals(obfuscator.obfuscateConfidentialData("5137004986396403", "6403"), "***MASKED***");
+        Assert.assertEquals(obfuscator.obfuscateConfidentialData("5137004986396403", "6403"), "************");
     }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscatorConverter.java b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscatorConverter.java
index 943a620..4d54512 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscatorConverter.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestObfuscatorConverter.java
@@ -54,9 +54,9 @@ public class TestObfuscatorConverter extends ServerTestSuiteNoDB {
                "</gateway>",
                "Starting purchase call: \n" +
                "<gateway>\n" +
-               "<card>***MASKED***1111</card>\n" +
-               "<bankAccountNumber>*MASKED**</bankAccountNumber>\n" +
-               "<password>**MASKED***</password>\n" +
+               "<card>411111******1111</card>\n" +
+               "<bankAccountNumber>*********</bankAccountNumber>\n" +
+               "<password>***********</password>\n" +
                "</gateway>");
     }
 
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestPatternObfuscator.java b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestPatternObfuscator.java
index 3476f58..11d9162 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestPatternObfuscator.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/server/log/obfuscators/TestPatternObfuscator.java
@@ -45,16 +45,16 @@ public class TestPatternObfuscator extends ServerTestSuiteNoDB {
                "</ns2:shopperName>\n",
                "<ns:expiryMonth>04</expiryMonth>\n" +
                "<ns:expiryYear>2015</expiryYear>\n" +
-               "<ns:holderName>*MASKED*</holderName>\n" +
-               "<ns:number>*****MASKED*****</number>\n" +
-               "<ns2:shopperEmail>****MASKED*****</ns2:shopperEmail>\n" +
+               "<ns:holderName>********</holderName>\n" +
+               "<ns:number>****************</number>\n" +
+               "<ns2:shopperEmail>***************</ns2:shopperEmail>\n" +
                "<ns2:shopperIP>127.0.0.1</ns2:shopperIP>\n" +
                "<ns2:shopperInteraction xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>\n" +
                "<ns2:shopperName>\n" +
-               "    <firstName>MASKED</firstName>\n" +
+               "    <firstName>***</firstName>\n" +
                "    <gender xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>\n" +
                "    <infix xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>\n" +
-               "    <lastName>MASKED</lastName>\n" +
+               "    <lastName>*****</lastName>\n" +
                "</ns2:shopperName>\n");
     }
 
@@ -131,25 +131,25 @@ public class TestPatternObfuscator extends ServerTestSuiteNoDB {
                "      <clientLibraryVersion>1.47.0</clientLibraryVersion>\n" +
                "      <clientEnvironment>java</clientEnvironment>\n" +
                "<billTo>\n" +
-               "  <firstName>MASKED</firstName>\n" +
-               "  <lastName>MASKED</lastName>\n" +
+               "  <firstName>****</firstName>\n" +
+               "  <lastName>***</lastName>\n" +
                "  <street1>5, oakriu road</street1>\n" +
                "  <street2>apt. 298</street2>\n" +
                "  <city>Gdio Foia</city>\n" +
                "  <state>FL</state>\n" +
                "  <postalCode>49302</postalCode>\n" +
                "  <country>US</country>\n" +
-               "  <email>**********MASKED**********</email>\n" +
+               "  <email>**************************</email>\n" +
                "</billTo>\n" +
                "<purchaseTotals>\n" +
                "  <currency>USD</currency>\n" +
                "  <grandTotalAmount>0.00</grandTotalAmount>\n" +
                "</purchaseTotals>\n" +
                "<card>\n" +
-               "  <accountNumber>*****MASKED*****</accountNumber>\n" +
+               "  <accountNumber>****************</accountNumber>\n" +
                "  <expirationMonth>12</expirationMonth>\n" +
                "  <expirationYear>2017</expirationYear>\n" +
-               "  <cvNumber>MASKED</cvNumber>\n" +
+               "  <cvNumber>****</cvNumber>\n" +
                "  <cardType>001</cardType>\n" +
                "</card>\n" +
                "<subscription>\n" +
@@ -171,7 +171,7 @@ public class TestPatternObfuscator extends ServerTestSuiteNoDB {
     @Test(groups = "fast")
     public void testLitle() throws Exception {
         verify("<litleOnlineRequest merchantId=\\\"merchant_id\\\" version=\\\"8.18\\\" xmlns=\\\"http://www.litle.com/schema\\\"><authentication><user>login</user><password>password</password></authentication><sale id=\\\"615b9cb3-8580-4f57-bf69-9\\\" reportGroup=\\\"Default Report Group\\\"><orderId>615b9cb3-8580-4f57-bf69-9</orderId><amount>10000</amount><orderSource>ecommerce</orderSource><billToAddress><name>John Doe</name><email>1428325948-test@tester.com</email><addressLine1>5, oakriu road</addressLine1><addressLine2>apt. 298</addressLine2><city>Gdio Foia</city><state>FL</state><zip>49302</zip><country>US</country></billToAddress><shipToAddress/><card><type>VI</type><number>4242424242424242</number><expDate>1217</expDate><cardValidationNum>1234</cardValidationNum></card></sale></litleOnlineRequest>",
-               "<litleOnlineRequest merchantId=\\\"merchant_id\\\" version=\\\"8.18\\\" xmlns=\\\"http://www.litle.com/schema\\\"><authentication><user>login</user><password>*MASKED*</password></authentication><sale id=\\\"615b9cb3-8580-4f57-bf69-9\\\" reportGroup=\\\"Default Report Group\\\"><orderId>615b9cb3-8580-4f57-bf69-9</orderId><amount>10000</amount><orderSource>ecommerce</orderSource><billToAddress><name>*MASKED*</name><email>**********MASKED**********</email><addressLine1>5, oakriu road</addressLine1><addressLine2>apt. 298</addressLine2><city>Gdio Foia</city><state>FL</state><zip>49302</zip><country>US</country></billToAddress><shipToAddress/><card><type>VI</type><number>*****MASKED*****</number><expDate>1217</expDate><cardValidationNum>MASKED</cardValidationNum></card></sale></litleOnlineRequest>");
+               "<litleOnlineRequest merchantId=\\\"merchant_id\\\" version=\\\"8.18\\\" xmlns=\\\"http://www.litle.com/schema\\\"><authentication><user>login</user><password>********</password></authentication><sale id=\\\"615b9cb3-8580-4f57-bf69-9\\\" reportGroup=\\\"Default Report Group\\\"><orderId>615b9cb3-8580-4f57-bf69-9</orderId><amount>10000</amount><orderSource>ecommerce</orderSource><billToAddress><name>********</name><email>**************************</email><addressLine1>5, oakriu road</addressLine1><addressLine2>apt. 298</addressLine2><city>Gdio Foia</city><state>FL</state><zip>49302</zip><country>US</country></billToAddress><shipToAddress/><card><type>VI</type><number>****************</number><expDate>1217</expDate><cardValidationNum>****</cardValidationNum></card></sale></litleOnlineRequest>");
     }
 
     @Test(groups = "fast")
@@ -203,7 +203,7 @@ public class TestPatternObfuscator extends ServerTestSuiteNoDB {
                "  \"card\": {\n" +
                "    \"id\": \"card_483etw4er9fg4vF3sQdrt3FG\",\n" +
                "    \"object\": \"card\",\n" +
-               "    \"banknumber\": *****MASKED*****,\n" +
+               "    \"banknumber\": ****************,\n" +
                "    \"last4\": \"0000\",\n" +
                "    \"brand\": \"Visa\",\n" +
                "    \"funding\": \"credit\",\n" +
@@ -211,7 +211,7 @@ public class TestPatternObfuscator extends ServerTestSuiteNoDB {
                "    \"exp_year\": 2019,\n" +
                "    \"fingerprint\": \"HOh74kZU387WlUvy\",\n" +
                "    \"country\": \"US\",\n" +
-               "    \"name\": **MASKED***,\n" +
+               "    \"name\": ***********,\n" +
                "    \"address_line1\": null,\n" +
                "    \"address_line2\": null,\n" +
                "    \"address_city\": null,\n" +
@@ -244,7 +244,7 @@ public class TestPatternObfuscator extends ServerTestSuiteNoDB {
                "</entry>\n",
                "<entry>\n" +
                "  <key xsi:type=\"xsd:string\">PayU.ccvv</key>\n" +
-               "  <value xsi:type=\"xsd:string\">MASKED</value>\n" +
+               "  <value xsi:type=\"xsd:string\">****</value>\n" +
                "</entry>\n" +
                "<entry>\n" +
                "  <key xsi:type=\"xsd:string\">PayU.ccnum</key>\n" +
@@ -263,7 +263,7 @@ public class TestPatternObfuscator extends ServerTestSuiteNoDB {
     @Test(groups = "fast", description = "Test for ActiveMerchant wiredump_device logging")
     public void testWithQuotedNewLines() throws Exception {
         verify("[cybersource-plugin] \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><accountNumber>4111111111111111</accountNumber>\\n  <expirationMonth>09</expirationMonth>\\n  \"",
-               "[cybersource-plugin] \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><accountNumber>*****MASKED*****</accountNumber>\\n  <expirationMonth>09</expirationMonth>\\n  \"");
+               "[cybersource-plugin] \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><accountNumber>****************</accountNumber>\\n  <expirationMonth>09</expirationMonth>\\n  \"");
     }
 
     @Test(groups = "fast")
diff --git a/profiles/killpay/pom.xml b/profiles/killpay/pom.xml
index 45a9a04..d08edaf 100644
--- a/profiles/killpay/pom.xml
+++ b/profiles/killpay/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>killbill-profiles</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-profiles-killpay</artifactId>

profiles/pom.xml 2(+1 -1)

diff --git a/profiles/pom.xml b/profiles/pom.xml
index a5a5e2d..7978092 100644
--- a/profiles/pom.xml
+++ b/profiles/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-profiles</artifactId>
diff --git a/subscription/pom.xml b/subscription/pom.xml
index abfbcaa..111ed11 100644
--- a/subscription/pom.xml
+++ b/subscription/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-subscription</artifactId>

tenant/pom.xml 2(+1 -1)

diff --git a/tenant/pom.xml b/tenant/pom.xml
index 8aec516..bfc6e8a 100644
--- a/tenant/pom.xml
+++ b/tenant/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-tenant</artifactId>

usage/pom.xml 2(+1 -1)

diff --git a/usage/pom.xml b/usage/pom.xml
index 602cdf0..44755bc 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-usage</artifactId>

util/pom.xml 2(+1 -1)

diff --git a/util/pom.xml b/util/pom.xml
index 6c8ffbf..6aa221c 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.17.6-SNAPSHOT</version>
+        <version>0.17.7-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-util</artifactId>
diff --git a/util/src/main/java/org/killbill/billing/util/export/dao/DatabaseExportDao.java b/util/src/main/java/org/killbill/billing/util/export/dao/DatabaseExportDao.java
index 7343dbf..5fe8093 100644
--- a/util/src/main/java/org/killbill/billing/util/export/dao/DatabaseExportDao.java
+++ b/util/src/main/java/org/killbill/billing/util/export/dao/DatabaseExportDao.java
@@ -23,17 +23,16 @@ import java.util.Map;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
-import org.skife.jdbi.v2.Handle;
-import org.skife.jdbi.v2.IDBI;
-import org.skife.jdbi.v2.ResultIterator;
-import org.skife.jdbi.v2.tweak.HandleCallback;
-
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.util.api.ColumnInfo;
 import org.killbill.billing.util.api.DatabaseExportOutputStream;
-import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.util.dao.TableName;
 import org.killbill.billing.util.validation.DefaultColumnInfo;
 import org.killbill.billing.util.validation.dao.DatabaseSchemaDao;
+import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.ResultIterator;
+import org.skife.jdbi.v2.tweak.HandleCallback;
 
 @Singleton
 public class DatabaseExportDao {
@@ -48,6 +47,33 @@ public class DatabaseExportDao {
         this.dbi = dbi;
     }
 
+    private enum TableType {
+        /* TableName.ACCOUNT */
+        KB_ACCOUNT("record_id", "tenant_record_id"),
+        /* Any per-account data table */
+        KB_PER_ACCOUNT("account_record_id", "tenant_record_id"),
+        /* bus_events, notifications table */
+        NOTIFICATION("search_key1", "search_key2"),
+        /* To be discarded */
+        OTHER(null, null);
+
+        private final String accountRecordIdColumnName;
+        private final String tenantRecordIdColumnName;
+
+        TableType(final String accountRecordIdColumnName, final String tenantRecordIdColumnName) {
+            this.accountRecordIdColumnName = accountRecordIdColumnName;
+            this.tenantRecordIdColumnName = tenantRecordIdColumnName;
+        }
+
+        public String getAccountRecordIdColumnName() {
+            return accountRecordIdColumnName;
+        }
+
+        public String getTenantRecordIdColumnName() {
+            return tenantRecordIdColumnName;
+        }
+    }
+
     public void exportDataForAccount(final DatabaseExportOutputStream out, final InternalTenantContext context) {
         if (context.getAccountRecordId() == null || context.getTenantRecordId() == null) {
             return;
@@ -72,8 +98,12 @@ public class DatabaseExportDao {
         exportDataForAccountAndTable(out, columnsForTable, context);
     }
 
+
     private void exportDataForAccountAndTable(final DatabaseExportOutputStream out, final List<ColumnInfo> columnsForTable, final InternalTenantContext context) {
-        boolean hasAccountRecordIdColumn = false;
+
+
+        final String tableName = columnsForTable.get(0).getTableName();
+        TableType tableType = TableName.ACCOUNT.getTableName().equals(tableName) ? TableType.KB_ACCOUNT : TableType.OTHER;
         boolean firstColumn = true;
         final StringBuilder queryBuilder = new StringBuilder("select ");
         for (final ColumnInfo column : columnsForTable) {
@@ -84,27 +114,29 @@ public class DatabaseExportDao {
             }
 
             queryBuilder.append(column.getColumnName());
-            if (column.getColumnName().equals("account_record_id")) {
-                hasAccountRecordIdColumn = true;
+
+            if (tableType == TableType.OTHER) {
+                if (column.getColumnName().equals(TableType.KB_PER_ACCOUNT.getAccountRecordIdColumnName())) {
+                    tableType = TableType.KB_PER_ACCOUNT;
+                } else if (column.getColumnName().equals(TableType.NOTIFICATION.getAccountRecordIdColumnName())) {
+                    tableType = TableType.NOTIFICATION;
+                }
             }
         }
 
-        final String tableName = columnsForTable.get(0).getTableName();
-        final boolean isAccountTable = TableName.ACCOUNT.getTableName().equals(tableName);
-
         // Don't export non-account specific tables
-        if (!isAccountTable && !hasAccountRecordIdColumn) {
+        if (tableType ==  TableType.OTHER) {
             return;
         }
 
         // Build the query - make sure to filter by account and tenant!
         queryBuilder.append(" from ")
-                    .append(tableName);
-        if (isAccountTable) {
-            queryBuilder.append(" where record_id = :accountRecordId and tenant_record_id = :tenantRecordId");
-        } else {
-            queryBuilder.append(" where account_record_id = :accountRecordId and tenant_record_id = :tenantRecordId");
-        }
+                    .append(tableName)
+                    .append(" where ")
+                    .append(tableType.getAccountRecordIdColumnName())
+                    .append(" = :accountRecordId and ")
+                    .append(tableType.getTenantRecordIdColumnName())
+                    .append("  = :tenantRecordId");
 
         // Notify the stream that we're about to write data for a different table
         out.newTable(tableName, columnsForTable);
@@ -124,7 +156,6 @@ public class DatabaseExportDao {
                 } finally {
                     iterator.close();
                 }
-
                 return null;
             }
         });