killbill-uncached

Merge branch 'work-for-release-0.17.x' of github.com:killbill/killbill

8/25/2016 8:38:30 PM

Details

diff --git a/invoice/src/main/java/org/killbill/billing/invoice/config/MultiTenantInvoiceConfig.java b/invoice/src/main/java/org/killbill/billing/invoice/config/MultiTenantInvoiceConfig.java
index 65f339f..79a0a45 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/config/MultiTenantInvoiceConfig.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/config/MultiTenantInvoiceConfig.java
@@ -17,14 +17,13 @@
 
 package org.killbill.billing.invoice.config;
 
-import java.lang.reflect.Method;
-
 import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.glue.InvoiceModule;
 import org.killbill.billing.util.config.definition.InvoiceConfig;
+import org.killbill.billing.util.config.definition.KillbillConfig;
 import org.killbill.billing.util.config.tenant.CacheConfig;
 import org.killbill.billing.util.config.tenant.MultiTenantConfigBase;
 import org.skife.config.TimeSpan;
@@ -46,8 +45,7 @@ public class MultiTenantInvoiceConfig extends MultiTenantConfigBase implements I
 
     @Override
     public int getNumberOfMonthsInFuture(final InternalTenantContext tenantContext) {
-        final Method method = new Object(){}.getClass().getEnclosingMethod();
-        final String result = getStringTenantConfig(method.getName(), tenantContext);
+        final String result = getStringTenantConfig("getNumberOfMonthsInFuture", tenantContext);
         if (result != null) {
             return Integer.parseInt(result);
         }
@@ -61,8 +59,7 @@ public class MultiTenantInvoiceConfig extends MultiTenantConfigBase implements I
 
     @Override
     public TimeSpan getDryRunNotificationSchedule(final InternalTenantContext tenantContext) {
-        final Method method = new Object(){}.getClass().getEnclosingMethod();
-        final String result = getStringTenantConfig(method.getName(), tenantContext);
+        final String result = getStringTenantConfig("getDryRunNotificationSchedule", tenantContext);
         if (result != null) {
             return new TimeSpan(result);
         }
@@ -76,8 +73,7 @@ public class MultiTenantInvoiceConfig extends MultiTenantConfigBase implements I
 
     @Override
     public int getMaxRawUsagePreviousPeriod(final InternalTenantContext tenantContext) {
-        final Method method = new Object(){}.getClass().getEnclosingMethod();
-        final String result = getStringTenantConfig(method.getName(), tenantContext);
+        final String result = getStringTenantConfig("getMaxRawUsagePreviousPeriod", tenantContext);
         if (result != null) {
             return Integer.parseInt(result);
         }
@@ -95,11 +91,7 @@ public class MultiTenantInvoiceConfig extends MultiTenantConfigBase implements I
     }
 
     @Override
-    protected Method getConfigStaticMethod(final String methodName) {
-        try {
-            return InvoiceConfig.class.getMethod(methodName, InternalTenantContext.class);
-        } catch (final NoSuchMethodException e) {
-            throw new RuntimeException(e);
-        }
+    protected Class<? extends KillbillConfig> getConfigClass() {
+        return InvoiceConfig.class;
     }
 }
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 7a6b6aa..ee09c1a 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
@@ -17,6 +17,7 @@
 package org.killbill.billing.jaxrs.util;
 
 import java.net.URI;
+import java.util.HashMap;
 import java.util.Map;
 
 import javax.annotation.Nullable;
@@ -33,6 +34,10 @@ import org.killbill.billing.util.config.definition.JaxrsConfig;
 public class JaxrsUriBuilder {
 
     private final JaxrsConfig jaxrsConfig;
+    private final Map<Class, UriBuilder> classToUriBuilder = new HashMap<Class, UriBuilder>();
+    private final Map<String, UriBuilder> classAndMethodToUriBuilder = new HashMap<String, UriBuilder>();
+    private final Map<String, UriBuilder> pathAndClassToUriBuilder = new HashMap<String, UriBuilder>();
+    private final Map<String, UriBuilder> pathClassAndMethodToUriBuilder = new HashMap<String, UriBuilder>();
 
     @Inject
     public JaxrsUriBuilder(JaxrsConfig jaxrsConfig) {
@@ -53,8 +58,8 @@ public class JaxrsUriBuilder {
 
         if (jaxrsConfig.isJaxrsLocationFullUrl()) {
             uriBuilder.scheme(uriInfo.getAbsolutePath().getScheme())
-              .host(uriInfo.getAbsolutePath().getHost())
-              .port(uriInfo.getAbsolutePath().getPort());
+                      .host(uriInfo.getAbsolutePath().getHost())
+                      .port(uriInfo.getAbsolutePath().getPort());
         }
         return objectId != null ? uriBuilder.build(objectId) : uriBuilder.build();
     }
@@ -92,15 +97,74 @@ public class JaxrsUriBuilder {
 
     private UriBuilder getUriBuilder(final String path, final Class<? extends JaxrsResource> theClassMaybeEnhanced, @Nullable final String getMethodName) {
         final Class theClass = getNonEnhancedClass(theClassMaybeEnhanced);
-        return getMethodName != null ? UriBuilder.fromPath(path.equals("/") ? path.substring(1) : path).path(theClass).path(theClass, getMethodName) :
-               UriBuilder.fromPath(path).path(theClass);
+        return getMethodName != null ? fromPath(path.equals("/") ? path.substring(1) : path, theClass, getMethodName) : fromPath(path, theClass);
+    }
+
+    private UriBuilder fromPath(final String path, final Class theClass, final String getMethodName) {
+        final String key = path + theClass.getName() + getMethodName;
+
+        UriBuilder uriBuilder = pathClassAndMethodToUriBuilder.get(key);
+        if (uriBuilder == null) {
+            synchronized (pathClassAndMethodToUriBuilder) {
+                uriBuilder = pathClassAndMethodToUriBuilder.get(key);
+                if (uriBuilder == null) {
+                    uriBuilder = fromPath(path, theClass).path(theClass, getMethodName);
+                    pathClassAndMethodToUriBuilder.put(key, uriBuilder);
+                }
+            }
+        }
+        return uriBuilder.clone();
+    }
+
+    private UriBuilder fromPath(final String path, final Class theClass) {
+        final String key = path + theClass.getName();
+
+        UriBuilder uriBuilder = pathAndClassToUriBuilder.get(key);
+        if (uriBuilder == null) {
+            synchronized (pathAndClassToUriBuilder) {
+                uriBuilder = pathAndClassToUriBuilder.get(key);
+                if (uriBuilder == null) {
+                    uriBuilder = UriBuilder.fromPath(path).path(theClass);
+                    pathAndClassToUriBuilder.put(key, uriBuilder);
+                }
+            }
+        }
+        return uriBuilder.clone();
     }
 
     private UriBuilder getUriBuilder(final Class<? extends JaxrsResource> theClassMaybeEnhanced, @Nullable final String getMethodName) {
         final Class theClass = getNonEnhancedClass(theClassMaybeEnhanced);
-        return getMethodName != null ? UriBuilder.fromResource(theClass).path(theClass, getMethodName) :
-               UriBuilder.fromResource(theClass);
+        return getMethodName != null ? fromResource(theClass, getMethodName) : fromResource(theClass);
+    }
 
+    private UriBuilder fromResource(final Class theClass, final String getMethodName) {
+        final String key = theClass.getName() + getMethodName;
+
+        UriBuilder uriBuilder = classAndMethodToUriBuilder.get(key);
+        if (uriBuilder == null) {
+            synchronized (classAndMethodToUriBuilder) {
+                uriBuilder = classAndMethodToUriBuilder.get(key);
+                if (uriBuilder == null) {
+                    uriBuilder = fromResource(theClass).path(theClass, getMethodName);
+                    classAndMethodToUriBuilder.put(key, uriBuilder);
+                }
+            }
+        }
+        return uriBuilder.clone();
+    }
+
+    private UriBuilder fromResource(final Class theClass) {
+        UriBuilder uriBuilder = classToUriBuilder.get(theClass);
+        if (uriBuilder == null) {
+            synchronized (classToUriBuilder) {
+                uriBuilder = classToUriBuilder.get(theClass);
+                if (uriBuilder == null) {
+                    uriBuilder = UriBuilder.fromResource(theClass);
+                    classToUriBuilder.put(theClass, uriBuilder);
+                }
+            }
+        }
+        return uriBuilder.clone();
     }
 
     private Class getNonEnhancedClass(final Class<? extends JaxrsResource> theClassMaybeEnhanced) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/config/MultiTenantPaymentConfig.java b/payment/src/main/java/org/killbill/billing/payment/config/MultiTenantPaymentConfig.java
index bbf365f..6e56c52 100644
--- a/payment/src/main/java/org/killbill/billing/payment/config/MultiTenantPaymentConfig.java
+++ b/payment/src/main/java/org/killbill/billing/payment/config/MultiTenantPaymentConfig.java
@@ -17,7 +17,6 @@
 
 package org.killbill.billing.payment.config;
 
-import java.lang.reflect.Method;
 import java.util.List;
 
 import javax.inject.Inject;
@@ -25,6 +24,7 @@ import javax.inject.Named;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.payment.glue.PaymentModule;
+import org.killbill.billing.util.config.definition.KillbillConfig;
 import org.killbill.billing.util.config.definition.PaymentConfig;
 import org.killbill.billing.util.config.tenant.CacheConfig;
 import org.killbill.billing.util.config.tenant.MultiTenantConfigBase;
@@ -48,11 +48,9 @@ public class MultiTenantPaymentConfig extends MultiTenantConfigBase implements P
 
     @Override
     public List<Integer> getPaymentFailureRetryDays(@Param("dummy") final InternalTenantContext tenantContext) {
-        // There is no good way to achieve that in java; this solution is expensive (we could consider hardcoding the method name each time instead)
-        final Method method = new Object() {}.getClass().getEnclosingMethod();
-        final String result = getStringTenantConfig(method.getName(), tenantContext);
+        final String result = getStringTenantConfig("getPaymentFailureRetryDays", tenantContext);
         if (result != null) {
-            return convertToListInteger(result, method.getName());
+            return convertToListInteger(result, "getPaymentFailureRetryDays");
         }
         return getPaymentFailureRetryDays();
     }
@@ -64,8 +62,7 @@ public class MultiTenantPaymentConfig extends MultiTenantConfigBase implements P
 
     @Override
     public int getPluginFailureInitialRetryInSec(@Param("dummy") final InternalTenantContext tenantContext) {
-        final Method method = new Object() {}.getClass().getEnclosingMethod();
-        final String result = getStringTenantConfig(method.getName(), tenantContext);
+        final String result = getStringTenantConfig("getPluginFailureInitialRetryInSec", tenantContext);
         if (result != null) {
             return Integer.parseInt(result);
         }
@@ -79,9 +76,7 @@ public class MultiTenantPaymentConfig extends MultiTenantConfigBase implements P
 
     @Override
     public int getPluginFailureRetryMultiplier(@Param("dummy") final InternalTenantContext tenantContext) {
-        final Method method = new Object() {}.getClass().getEnclosingMethod();
-
-        final String result = getStringTenantConfig(method.getName(), tenantContext);
+        final String result = getStringTenantConfig("getPluginFailureRetryMultiplier", tenantContext);
         if (result != null) {
             return Integer.parseInt(result);
         }
@@ -95,11 +90,9 @@ public class MultiTenantPaymentConfig extends MultiTenantConfigBase implements P
 
     @Override
     public List<TimeSpan> getIncompleteTransactionsRetries(@Param("dummy") final InternalTenantContext tenantContext) {
-        final Method method = new Object() {}.getClass().getEnclosingMethod();
-
-        final String result = getStringTenantConfig(method.getName(), tenantContext);
+        final String result = getStringTenantConfig("getIncompleteTransactionsRetries", tenantContext);
         if (result != null) {
-            return convertToListTimeSpan(result, method.getName());
+            return convertToListTimeSpan(result, "getIncompleteTransactionsRetries");
         }
         return getIncompleteTransactionsRetries();
     }
@@ -111,9 +104,7 @@ public class MultiTenantPaymentConfig extends MultiTenantConfigBase implements P
 
     @Override
     public int getPluginFailureRetryMaxAttempts(@Param("dummy") final InternalTenantContext tenantContext) {
-        final Method method = new Object() {}.getClass().getEnclosingMethod();
-
-        final String result = getStringTenantConfig(method.getName(), tenantContext);
+        final String result = getStringTenantConfig("getPluginFailureRetryMaxAttempts", tenantContext);
         if (result != null) {
             return Integer.parseInt(result);
         }
@@ -127,11 +118,9 @@ public class MultiTenantPaymentConfig extends MultiTenantConfigBase implements P
 
     @Override
     public List<String> getPaymentControlPluginNames(@Param("dummy") final InternalTenantContext tenantContext) {
-        final Method method = new Object() {}.getClass().getEnclosingMethod();
-
-        final String result = getStringTenantConfig(method.getName(), tenantContext);
+        final String result = getStringTenantConfig("getPaymentControlPluginNames", tenantContext);
         if (result != null) {
-            return convertToListString(result, method.getName());
+            return convertToListString(result, "getPaymentControlPluginNames");
         }
         return getPaymentControlPluginNames();
     }
@@ -167,11 +156,7 @@ public class MultiTenantPaymentConfig extends MultiTenantConfigBase implements P
     }
 
     @Override
-    protected Method getConfigStaticMethod(final String methodName) {
-        try {
-            return PaymentConfig.class.getMethod(methodName, InternalTenantContext.class);
-        } catch (final NoSuchMethodException e) {
-            throw new RuntimeException(e);
-        }
+    protected Class<? extends KillbillConfig> getConfigClass() {
+        return PaymentConfig.class;
     }
 }
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/config/MultiTenantNotificationConfig.java b/profiles/killbill/src/main/java/org/killbill/billing/server/config/MultiTenantNotificationConfig.java
index cfea29b..08ffd8a 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/config/MultiTenantNotificationConfig.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/config/MultiTenantNotificationConfig.java
@@ -18,10 +18,13 @@
 package org.killbill.billing.server.config;
 
 import java.lang.reflect.Method;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.payment.glue.PaymentModule;
+import org.killbill.billing.util.config.definition.KillbillConfig;
 import org.killbill.billing.util.config.definition.NotificationConfig;
 import org.killbill.billing.util.config.tenant.CacheConfig;
 import org.killbill.billing.util.config.tenant.MultiTenantConfigBase;
@@ -33,6 +36,7 @@ import com.google.inject.name.Named;
 
 public class MultiTenantNotificationConfig extends MultiTenantConfigBase implements NotificationConfig {
 
+    private final Map<String, Method> methodsCache = new HashMap<String, Method>();
     private final NotificationConfig staticConfig;
 
     @Inject
@@ -42,27 +46,21 @@ public class MultiTenantNotificationConfig extends MultiTenantConfigBase impleme
     }
 
     @Override
-    protected Method getConfigStaticMethod(final String methodName) {
-        try {
-            return NotificationConfig.class.getMethod(methodName, InternalTenantContext.class);
-        } catch (final NoSuchMethodException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Override
     public List<TimeSpan> getPushNotificationsRetries() {
         return staticConfig.getPushNotificationsRetries();
     }
 
     @Override
     public List<TimeSpan> getPushNotificationsRetries(@Param("dummy") final InternalTenantContext tenantContext) {
-        final Method method = new Object() {}.getClass().getEnclosingMethod();
-
-        final String result = getStringTenantConfig(method.getName(), tenantContext);
+        final String result = getStringTenantConfig("getPushNotificationsRetries", tenantContext);
         if (result != null) {
-            return convertToListTimeSpan(result, method.getName());
+            return convertToListTimeSpan(result, "getPushNotificationsRetries");
         }
         return getPushNotificationsRetries();
     }
+
+    @Override
+    protected Class<? extends KillbillConfig> getConfigClass() {
+        return NotificationConfig.class;
+    }
 }
diff --git a/util/src/main/java/org/killbill/billing/util/config/tenant/MultiTenantConfigBase.java b/util/src/main/java/org/killbill/billing/util/config/tenant/MultiTenantConfigBase.java
index 87f0b0a..39562ee 100644
--- a/util/src/main/java/org/killbill/billing/util/config/tenant/MultiTenantConfigBase.java
+++ b/util/src/main/java/org/killbill/billing/util/config/tenant/MultiTenantConfigBase.java
@@ -18,9 +18,12 @@
 package org.killbill.billing.util.config.tenant;
 
 import java.lang.reflect.Method;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.config.definition.KillbillConfig;
 import org.skife.config.Config;
 import org.skife.config.Separator;
 import org.skife.config.TimeSpan;
@@ -31,6 +34,7 @@ import com.google.common.collect.Iterables;
 
 public abstract class MultiTenantConfigBase {
 
+    private final Map<String, Method> methodsCache = new HashMap<String, Method>();
     protected final CacheConfig cacheConfig;
 
     private final static Function<String, Integer> INT_CONVERTER = new Function<String, Integer>() {
@@ -107,5 +111,23 @@ public abstract class MultiTenantConfigBase {
         return ImmutableList.copyOf(value.split(separator == null ? Separator.DEFAULT : separator.value()));
     }
 
-    protected abstract Method getConfigStaticMethod(final String methodName);
+    protected Method getConfigStaticMethod(final String methodName) {
+        Method method = methodsCache.get(methodName);
+        if (method == null) {
+            synchronized (methodsCache) {
+                method = methodsCache.get(methodName);
+                if (method == null) {
+                    try {
+                        method = getConfigClass().getMethod(methodName, InternalTenantContext.class);
+                        methodsCache.put(methodName, method);
+                    } catch (final NoSuchMethodException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+        }
+        return method;
+    }
+
+    protected abstract Class<? extends KillbillConfig> getConfigClass();
 }
diff --git a/util/src/main/java/org/killbill/billing/util/security/AnnotationHierarchicalResolver.java b/util/src/main/java/org/killbill/billing/util/security/AnnotationHierarchicalResolver.java
index 3973932..7ae7360 100644
--- a/util/src/main/java/org/killbill/billing/util/security/AnnotationHierarchicalResolver.java
+++ b/util/src/main/java/org/killbill/billing/util/security/AnnotationHierarchicalResolver.java
@@ -18,6 +18,7 @@ package org.killbill.billing.util.security;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.WeakHashMap;
 
@@ -26,13 +27,26 @@ import org.apache.shiro.aop.MethodInvocation;
 
 public class AnnotationHierarchicalResolver implements AnnotationResolver {
 
+    private final Map<String, Annotation> methodToAnnotation = new HashMap<String, Annotation>();
+
     @Override
     public Annotation getAnnotation(final MethodInvocation mi, final Class<? extends Annotation> clazz) {
         return getAnnotationFromMethod(mi.getMethod(), clazz);
     }
 
     public Annotation getAnnotationFromMethod(final Method method, final Class<? extends Annotation> clazz) {
-        return findAnnotation(method, clazz);
+        final String key = method.toString();
+        Annotation annotation = methodToAnnotation.get(key);
+        if (annotation == null) {
+            synchronized (methodToAnnotation) {
+                annotation = methodToAnnotation.get(key);
+                if (annotation == null) {
+                    annotation = findAnnotation(method, clazz);
+                    methodToAnnotation.put(key, annotation);
+                }
+            }
+        }
+        return annotation;
     }
 
     // The following comes from spring-core (AnnotationUtils) to handle annotations on interfaces