killbill-memoizeit
Details
.idea/dictionaries/pierre.xml 1(+1 -0)
diff --git a/.idea/dictionaries/pierre.xml b/.idea/dictionaries/pierre.xml
index e586f6b..b1bb5c9 100644
--- a/.idea/dictionaries/pierre.xml
+++ b/.idea/dictionaries/pierre.xml
@@ -2,6 +2,7 @@
<dictionary name="pierre">
<words>
<w>aoped</w>
+ <w>guice</w>
<w>jdbc</w>
<w>killbill</w>
<w>shiro</w>
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index e5836ee..79d5ebb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,7 +19,7 @@
<parent>
<artifactId>killbill-oss-parent</artifactId>
<groupId>com.ning.billing</groupId>
- <version>0.4.15</version>
+ <version>0.4.16</version>
</parent>
<artifactId>killbill</artifactId>
<version>0.6.17-SNAPSHOT</version>
server/pom.xml 9(+9 -0)
diff --git a/server/pom.xml b/server/pom.xml
index cf6afb6..760dd3a 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -25,6 +25,10 @@
<artifactId>killbill-server</artifactId>
<packaging>war</packaging>
<name>killbill-server</name>
+ <properties>
+ <!-- http://jira.codehaus.org/browse/MRESOURCES-99 -->
+ <build.timestamp>${maven.build.timestamp}</build.timestamp>
+ </properties>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
@@ -37,6 +41,10 @@
<scope>runtime</scope>
</dependency>
<dependency>
+ <groupId>com.dmurph</groupId>
+ <artifactId>JGoogleAnalyticsTracker</artifactId>
+ </dependency>
+ <dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>compile</scope>
@@ -283,6 +291,7 @@
<build>
<resources>
<resource>
+ <filtering>true</filtering>
<directory>${basedir}/src/main/resources</directory>
</resource>
</resources>
diff --git a/server/src/main/java/com/ning/billing/server/config/KillbillServerConfig.java b/server/src/main/java/com/ning/billing/server/config/KillbillServerConfig.java
index 7ca5c94..dca993b 100644
--- a/server/src/main/java/com/ning/billing/server/config/KillbillServerConfig.java
+++ b/server/src/main/java/com/ning/billing/server/config/KillbillServerConfig.java
@@ -16,6 +16,21 @@
package com.ning.billing.server.config;
-public interface KillbillServerConfig {
+import org.skife.config.Config;
+import org.skife.config.Default;
+import org.skife.config.Description;
+import com.ning.billing.util.config.KillbillConfig;
+
+public interface KillbillServerConfig extends KillbillConfig {
+
+ @Config("killbill.server.multitenant")
+ @Default("true")
+ @Description("Whether multi-tenancy is enabled")
+ public boolean isMultiTenancyEnabled();
+
+ @Config("killbill.server.test.mode")
+ @Default("false")
+ @Description("Whether to start in test mode")
+ public boolean isTestModeEnabled();
}
diff --git a/server/src/main/java/com/ning/billing/server/config/UpdateCheckConfig.java b/server/src/main/java/com/ning/billing/server/config/UpdateCheckConfig.java
new file mode 100644
index 0000000..713cdcc
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/config/UpdateCheckConfig.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.server.config;
+
+import java.net.URI;
+
+import org.skife.config.Config;
+import org.skife.config.Default;
+import org.skife.config.Description;
+
+import com.ning.billing.util.config.KillbillConfig;
+
+public interface UpdateCheckConfig extends KillbillConfig {
+
+ @Config("killbill.server.updateCheck.skip")
+ @Default("false")
+ @Description("Whether to skip update checks")
+ public boolean shouldSkipUpdateCheck();
+
+ @Config("killbill.server.updateCheck.url")
+ @Default("https://raw.github.com/killbill/killbill/master/server/src/main/resources/update-checker/killbill-server-update-list.properties")
+ @Description("URL to retrieve the latest version of Kill Bill")
+ public URI updateCheckURL();
+
+ @Config("killbill.server.updateCheck.connectTimeout")
+ @Default("3000")
+ @Description("Update check connection timeout")
+ public int updateCheckConnectionTimeout();
+}
diff --git a/server/src/main/java/com/ning/billing/server/filters/KillbillGuiceFilter.java b/server/src/main/java/com/ning/billing/server/filters/KillbillGuiceFilter.java
new file mode 100644
index 0000000..1a65128
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/filters/KillbillGuiceFilter.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.server.filters;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.server.updatechecker.UpdateChecker;
+
+import com.google.inject.servlet.GuiceFilter;
+
+public class KillbillGuiceFilter extends GuiceFilter {
+
+ private static final Logger log = LoggerFactory.getLogger(KillbillGuiceFilter.class);
+
+ private final UpdateChecker checker = new UpdateChecker();
+
+ @Override
+ public void init(final FilterConfig filterConfig) throws ServletException {
+ super.init(filterConfig);
+
+ // At this point, Kill Bill server is fully initialized
+ log.info("Kill Bill server has started");
+
+ checker.check(filterConfig.getServletContext());
+ }
+}
diff --git a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
index 923560c..6821eeb 100644
--- a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
+++ b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
@@ -22,6 +22,7 @@ import javax.management.MBeanServer;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
+import org.skife.config.ConfigurationObjectFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -47,17 +48,15 @@ import net.sf.ehcache.management.ManagementService;
public class KillbillGuiceListener extends SetupServer {
public static final Logger logger = LoggerFactory.getLogger(KillbillGuiceListener.class);
- public static final String KILLBILL_MULTITENANT_PROPERTY = "killbill.server.multitenant";
- public static final String KILLBILL_TEST_MODE_PROPERTY = "killbill.server.test.mode";
+ private KillbillServerConfig config;
private Injector injector;
private DefaultLifecycle killbillLifecycle;
private BusService killbillBusService;
private KillbillEventHandler killbilleventHandler;
protected Module getModule(final ServletContext servletContext) {
- final boolean testModeEnabled = Boolean.parseBoolean(System.getProperty(KILLBILL_TEST_MODE_PROPERTY, "false"));
- return new KillbillServerModule(servletContext, testModeEnabled);
+ return new KillbillServerModule(servletContext, config.isTestModeEnabled());
}
private void registerMBeansForCache(final CacheManager cacheManager) {
@@ -69,7 +68,7 @@ public class KillbillGuiceListener extends SetupServer {
@Override
public void contextInitialized(final ServletContextEvent event) {
- final boolean multitenant = Boolean.parseBoolean(System.getProperty(KILLBILL_MULTITENANT_PROPERTY, "true"));
+ config = new ConfigurationObjectFactory(System.getProperties()).build(KillbillServerConfig.class);
final ServerModuleBuilder builder = new ServerModuleBuilder()
.addConfig(KillbillServerConfig.class)
@@ -84,7 +83,7 @@ public class KillbillGuiceListener extends SetupServer {
.addJerseyResource("com.ning.billing.jaxrs.mappers")
.addJerseyResource("com.ning.billing.jaxrs.resources");
- if (multitenant) {
+ if (config.isMultiTenancyEnabled()) {
builder.addFilter("/*", TenantFilter.class);
}
diff --git a/server/src/main/java/com/ning/billing/server/updatechecker/ClientInfo.java b/server/src/main/java/com/ning/billing/server/updatechecker/ClientInfo.java
new file mode 100644
index 0000000..1cb9f21
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/updatechecker/ClientInfo.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.server.updatechecker;
+
+import java.net.InetAddress;
+import java.util.Properties;
+
+import javax.servlet.ServletContext;
+
+import com.google.common.base.StandardSystemProperty;
+import com.google.common.base.Strings;
+
+/**
+ * Gather client-side information
+ * <p/>
+ * We try not to gather any personally identifiable information, only
+ * specifications about the installation (OS, JVM). This helps us
+ * focus our development efforts.
+ */
+public class ClientInfo {
+
+ private static final String UNKNOWN = "UNKNOWN";
+
+ private static int CLIENT_ID;
+
+ static {
+ try {
+ CLIENT_ID = InetAddress.getLocalHost().hashCode();
+ } catch (Throwable t) {
+ CLIENT_ID = 0;
+ }
+ }
+
+ private final ServletContext servletContext;
+ private final Properties props;
+
+ public ClientInfo(final ServletContext servletContext) {
+ this.servletContext = servletContext;
+ this.props = System.getProperties();
+ }
+
+ public String getServletMajorVersion() {
+ return getSanitizedString(String.valueOf(servletContext.getMajorVersion()));
+ }
+
+ public String getServletMinorVersion() {
+ return getSanitizedString(String.valueOf(servletContext.getMinorVersion()));
+ }
+
+ public String getServletEffectiveMajorVersion() {
+ return getSanitizedString(String.valueOf(servletContext.getEffectiveMajorVersion()));
+ }
+
+ public String getServletEffectiveMinorVersion() {
+ return getSanitizedString(String.valueOf(servletContext.getEffectiveMinorVersion()));
+ }
+
+ public String getServerInfo() {
+ return getSanitizedString(servletContext.getServerInfo());
+ }
+
+ public String getClientId() {
+ return String.valueOf(CLIENT_ID);
+ }
+
+ public String getJavaVersion() {
+ return getProperty(StandardSystemProperty.JAVA_VERSION);
+ }
+
+ public String getJavaVendor() {
+ return getProperty(StandardSystemProperty.JAVA_VENDOR);
+ }
+
+ public String getJavaVendorURL() {
+ return getProperty(StandardSystemProperty.JAVA_VENDOR_URL);
+ }
+
+ public String getJavaVMSpecificationVersion() {
+ return getProperty(StandardSystemProperty.JAVA_VM_SPECIFICATION_VERSION);
+ }
+
+ public String getJavaVMSpecificationVendor() {
+ return getProperty(StandardSystemProperty.JAVA_VM_SPECIFICATION_VENDOR);
+ }
+
+ public String getJavaVMSpecificationName() {
+ return getProperty(StandardSystemProperty.JAVA_VM_SPECIFICATION_NAME);
+ }
+
+ public String getJavaVMVersion() {
+ return getProperty(StandardSystemProperty.JAVA_VM_VERSION);
+ }
+
+ public String getJavaVMVendor() {
+ return getProperty(StandardSystemProperty.JAVA_VM_VENDOR);
+ }
+
+ public String getJavaVMName() {
+ return getProperty(StandardSystemProperty.JAVA_VM_NAME);
+ }
+
+ public String getJavaSpecificationVersion() {
+ return getProperty(StandardSystemProperty.JAVA_SPECIFICATION_VERSION);
+ }
+
+ public String getJavaSpecificationVendor() {
+ return getProperty(StandardSystemProperty.JAVA_SPECIFICATION_VENDOR);
+ }
+
+ public String getJavaSpecificationName() {
+ return getProperty(StandardSystemProperty.JAVA_SPECIFICATION_NAME);
+ }
+
+ public String getJavaClassVersion() {
+ return getProperty(StandardSystemProperty.JAVA_CLASS_VERSION);
+ }
+
+ public String getJavaCompiler() {
+ return getProperty(StandardSystemProperty.JAVA_COMPILER);
+ }
+
+ public String getPlatform() {
+ return getProperty(StandardSystemProperty.OS_ARCH);
+ }
+
+ public String getOSName() {
+ return getProperty(StandardSystemProperty.OS_NAME);
+ }
+
+ public String getOSArch() {
+ return getProperty(StandardSystemProperty.OS_ARCH);
+ }
+
+ public String getOSVersion() {
+ return getProperty(StandardSystemProperty.OS_VERSION);
+ }
+
+ private String getProperty(final StandardSystemProperty standardKey) {
+ return getSanitizedString(props.getProperty(standardKey.key(), UNKNOWN));
+ }
+
+ private String getSanitizedString(final String string) {
+ return Strings.isNullOrEmpty(string) ? UNKNOWN : string.trim();
+ }
+}
diff --git a/server/src/main/java/com/ning/billing/server/updatechecker/ProductInfo.java b/server/src/main/java/com/ning/billing/server/updatechecker/ProductInfo.java
new file mode 100644
index 0000000..ff0fac4
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/updatechecker/ProductInfo.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.server.updatechecker;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Strings;
+import com.google.common.io.InputSupplier;
+import com.google.common.io.Resources;
+
+/**
+ * Kill Bill specific information
+ * <p/>
+ * At build time, we generated a magic file (version.properties) which should be on the classpath.
+ */
+public class ProductInfo {
+
+ private static final Logger log = LoggerFactory.getLogger(ProductInfo.class);
+
+ private static final String KILLBILL_SERVER_VERSION_RESOURCE = "/com/ning/billing/server/version.properties";
+
+ private static final String UNKNOWN = "UNKNOWN";
+
+ private static final String PRODUCT_NAME = "product-name";
+ private static final String VERSION = "version";
+ private static final String BUILT_BY = "built-by";
+ private static final String BUILD_JDK = "build-jdk";
+ private static final String BUILD_TIME = "build-time";
+ private static final String ENTERPRISE = "enterprise";
+
+ private final Properties props = new Properties();
+
+ public ProductInfo() {
+ try {
+ parseProductInfo(KILLBILL_SERVER_VERSION_RESOURCE);
+ } catch (IOException e) {
+ log.debug("Unable to detect current product info", e);
+ }
+ }
+
+ private void parseProductInfo(final String resource) throws IOException {
+ final URL resourceURL = Resources.getResource(resource);
+ final InputSupplier<InputStreamReader> inputSupplier = Resources.newReaderSupplier(resourceURL, Charset.forName("UTF-8"));
+ props.load(inputSupplier.getInput());
+ }
+
+ public String getName() {
+ return getProperty(PRODUCT_NAME);
+ }
+
+ public String getVersion() {
+ return getProperty(VERSION);
+ }
+
+ public String getBuiltBy() {
+ return getProperty(BUILT_BY);
+ }
+
+ public String getBuildJdk() {
+ return getProperty(BUILD_JDK);
+ }
+
+ public String getBuildTime() {
+ return getProperty(BUILD_TIME);
+ }
+
+ public boolean isEnterprise() {
+ return Boolean.parseBoolean(props.getProperty(ENTERPRISE));
+ }
+
+ private String getProperty(final String key) {
+ return getSanitizedString(props.getProperty(key, UNKNOWN));
+ }
+
+ private String getSanitizedString(final String string) {
+ return Strings.isNullOrEmpty(string) ? UNKNOWN : string.trim();
+ }
+
+ @Override
+ public String toString() {
+ final String fullProductName = String.format("%s (%s)", getName(), isEnterprise() ? "enterprise" : "community");
+ return String.format("%s version %s was built on %s, with jdk %s by %s",
+ fullProductName, getVersion(), getBuildTime(), getBuildJdk(), getBuiltBy());
+ }
+}
diff --git a/server/src/main/java/com/ning/billing/server/updatechecker/Tracker.java b/server/src/main/java/com/ning/billing/server/updatechecker/Tracker.java
new file mode 100644
index 0000000..bef870a
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/updatechecker/Tracker.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.server.updatechecker;
+
+import javax.servlet.ServletContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.server.config.UpdateCheckConfig;
+
+import com.dmurph.tracking.AnalyticsConfigData;
+import com.dmurph.tracking.JGoogleAnalyticsTracker;
+import com.dmurph.tracking.JGoogleAnalyticsTracker.GoogleAnalyticsVersion;
+
+public class Tracker {
+
+ private static final Logger log = LoggerFactory.getLogger(Tracker.class);
+ private static final String TRACKING_CODE = "UA-44821278-1";
+
+ // Information about this version of Kill Bill
+ final ProductInfo productInfo;
+ // Information about this JVM
+ private final ClientInfo clientInfo;
+ private final JGoogleAnalyticsTracker tracker;
+
+ public Tracker(final ProductInfo productInfo, final ServletContext context) {
+ this.productInfo = productInfo;
+ this.clientInfo = new ClientInfo(context);
+
+ final AnalyticsConfigData analyticsConfigData = new AnalyticsConfigData(TRACKING_CODE);
+ this.tracker = new JGoogleAnalyticsTracker(analyticsConfigData, GoogleAnalyticsVersion.V_4_7_2);
+ }
+
+ public void track() {
+ trackProperty("product", "name", productInfo.getName());
+ trackProperty("product", "version", productInfo.getVersion());
+ trackProperty("product", "builtBy", productInfo.getBuiltBy());
+ trackProperty("product", "buildJdk", productInfo.getBuildJdk());
+ trackProperty("product", "buildTime", productInfo.getBuildTime());
+ trackProperty("product", "enterprise", String.valueOf(productInfo.isEnterprise()));
+
+ trackProperty("client", "servletMajorVersion", clientInfo.getServletMajorVersion());
+ trackProperty("client", "servletMinorVersion", clientInfo.getServletMinorVersion());
+ trackProperty("client", "servletEffectiveMajorVersion", clientInfo.getServletEffectiveMajorVersion());
+ trackProperty("client", "servletEffectiveMinorVersion", clientInfo.getServletEffectiveMinorVersion());
+ trackProperty("client", "serverInfo", clientInfo.getServerInfo());
+ trackProperty("client", "clientId", clientInfo.getClientId());
+ trackProperty("client", "javaVersion", clientInfo.getJavaVersion());
+ trackProperty("client", "javaVendor", clientInfo.getJavaVendor());
+ trackProperty("client", "javaVendorURL", clientInfo.getJavaVendorURL());
+ trackProperty("client", "javaVMSpecificationVersion", clientInfo.getJavaVMSpecificationVersion());
+ trackProperty("client", "javaVMSpecificationVendor", clientInfo.getJavaVMSpecificationVendor());
+ trackProperty("client", "javaVMSpecificationName", clientInfo.getJavaVMSpecificationName());
+ trackProperty("client", "javaVMVersion", clientInfo.getJavaVMVersion());
+ trackProperty("client", "javaVMVendor", clientInfo.getJavaVMVendor());
+ trackProperty("client", "javaVMName", clientInfo.getJavaVMName());
+ trackProperty("client", "javaSpecificationVersion", clientInfo.getJavaSpecificationVersion());
+ trackProperty("client", "javaSpecificationVendor", clientInfo.getJavaSpecificationVendor());
+ trackProperty("client", "javaSpecificationName", clientInfo.getJavaSpecificationName());
+ trackProperty("client", "javaClassVersion", clientInfo.getJavaClassVersion());
+ trackProperty("client", "javaCompiler", clientInfo.getJavaCompiler());
+ trackProperty("client", "platform", clientInfo.getPlatform());
+ trackProperty("client", "osName", clientInfo.getOSName());
+ trackProperty("client", "osArch", clientInfo.getOSArch());
+ trackProperty("client", "osVersion", clientInfo.getOSVersion());
+ }
+
+ private void trackProperty(final String category, final String key, final String value) {
+ // Workaround for https://code.google.com/p/analytics-issues/issues/detail?id=219
+ String sanitizedValue = value;
+ sanitizedValue = sanitizedValue.replace('(', '-');
+ sanitizedValue = sanitizedValue.replace(')', '-');
+
+ log.debug("Tracking {}: {}={}", category, key, sanitizedValue);
+ tracker.trackEvent(category, key, sanitizedValue);
+ }
+}
diff --git a/server/src/main/java/com/ning/billing/server/updatechecker/UpdateChecker.java b/server/src/main/java/com/ning/billing/server/updatechecker/UpdateChecker.java
new file mode 100644
index 0000000..970341e
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/updatechecker/UpdateChecker.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.server.updatechecker;
+
+import java.io.IOException;
+
+import javax.servlet.ServletContext;
+
+import org.skife.config.ConfigurationObjectFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.server.config.UpdateCheckConfig;
+
+public class UpdateChecker {
+
+ private static final Logger log = LoggerFactory.getLogger(UpdateChecker.class);
+
+ final UpdateCheckConfig config = new ConfigurationObjectFactory(System.getProperties()).build(UpdateCheckConfig.class);
+
+ public void check(final ServletContext servletContext) {
+ log.info("For Kill Bill Commercial Support, visit http://thebillingproject.com or send an email to support@thebillingproject.com");
+
+ if (shouldSkipUpdateCheck()) {
+ return;
+ }
+
+ final Thread t = new Thread() {
+ @Override
+ public void run() {
+ try {
+ doCheck(servletContext);
+ } catch (IOException e) {
+ // Don't pollute logs, maybe no internet access?
+ log.debug("Unable to perform update check", e);
+ }
+ }
+ };
+ t.setDaemon(true);
+ t.run();
+ }
+
+ private void doCheck(final ServletContext servletContext) throws IOException {
+ // Information about this version of Kill Bill
+ final ProductInfo productInfo = new ProductInfo();
+ // Information about other versions of Kill Bill
+ final UpdateListProperties updateListProperties = new UpdateListProperties(config.updateCheckURL().toURL(), config.updateCheckConnectionTimeout());
+
+ // Log generic information about Kill Bill
+ if (updateListProperties.getGeneralNotice() != null) {
+ log.info(updateListProperties.getGeneralNotice());
+ }
+
+ // Log generic information about this release
+ if (updateListProperties.getNoticeForVersion(productInfo.getVersion()) != null) {
+ log.info(updateListProperties.getNoticeForVersion(productInfo.getVersion()));
+ }
+
+ // Log if there is a new version of Kill Bill available
+ final StringBuilder updates = new StringBuilder();
+ for (final String update : updateListProperties.getUpdatesForVersion(productInfo.getVersion())) {
+ if (updates.length() > 0) {
+ updates.append(", ");
+ }
+
+ updates.append(update);
+ final String changeLog = updateListProperties.getReleaseNotesForVersion(update);
+ if (changeLog != null) {
+ updates.append(" [").append(changeLog).append("]");
+ }
+ }
+ if (updates.length() > 0) {
+ log.info("New update(s) found: " + updates.toString() + ". Please check http://kill-bill.org for the latest version.");
+ }
+
+ // Send anonymous data
+ final Tracker tracker = new Tracker(productInfo, servletContext);
+ tracker.track();
+ }
+
+
+ private boolean shouldSkipUpdateCheck() {
+ if (config.shouldSkipUpdateCheck()) {
+ return true;
+ }
+
+ try {
+ Class.forName("org.testng.Assert");
+ return true;
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+}
diff --git a/server/src/main/java/com/ning/billing/server/updatechecker/UpdateListProperties.java b/server/src/main/java/com/ning/billing/server/updatechecker/UpdateListProperties.java
new file mode 100644
index 0000000..b7c4061
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/updatechecker/UpdateListProperties.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.server.updatechecker;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.List;
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+
+public class UpdateListProperties {
+
+ private static final Logger log = LoggerFactory.getLogger(UpdateListProperties.class);
+
+ private static final Splitter SPLITTER = Splitter.on(",").trimResults().omitEmptyStrings();
+
+ private final Properties properties = new Properties();
+
+ public UpdateListProperties(final URL updateCheckURL, final int connectionTimeout) {
+ try {
+ loadUpdateListProperties(updateCheckURL, connectionTimeout);
+ } catch (IOException e) {
+ log.debug("Unable to load update list properties", e);
+ }
+ }
+
+ public String getGeneralNotice() {
+ return getProperty("general.notice");
+ }
+
+ public String getNoticeForVersion(final String version) {
+ return getProperty(version + ".notice");
+ }
+
+ public List<String> getUpdatesForVersion(final String version) {
+ final String updates = getProperty(version + ".updates");
+ return updates == null ? ImmutableList.<String>of() : SPLITTER.splitToList(updates);
+ }
+
+ public String getReleaseNotesForVersion(final String version) {
+ return getProperty(version + ".release-notes");
+ }
+
+ private String getProperty(final String key) {
+ return getSanitizedString(properties.getProperty(key));
+ }
+
+ private String getSanitizedString(final String string) {
+ return Strings.isNullOrEmpty(string) ? null : string.trim();
+ }
+
+ private void loadUpdateListProperties(final URL updateCheckURL, final int connectionTimeout) throws IOException {
+ log.debug("Checking {} for updates", updateCheckURL.toExternalForm());
+ final URLConnection connection = updateCheckURL.openConnection();
+ connection.setConnectTimeout(connectionTimeout);
+
+ final InputStream in = connection.getInputStream();
+ try {
+ properties.load(in);
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ }
+ }
+}
diff --git a/server/src/main/resources/com/ning/billing/server/version.properties b/server/src/main/resources/com/ning/billing/server/version.properties
new file mode 100644
index 0000000..3ea3ec3
--- /dev/null
+++ b/server/src/main/resources/com/ning/billing/server/version.properties
@@ -0,0 +1,6 @@
+product-name = ${project.name}
+version = ${project.version}
+built-by = ${user.name}
+build-jdk = ${java.version}
+build-time = ${build.timestamp}
+enterprise = false
diff --git a/server/src/main/resources/update-checker/killbill-server-update-list.properties b/server/src/main/resources/update-checker/killbill-server-update-list.properties
new file mode 100644
index 0000000..4502bcb
--- /dev/null
+++ b/server/src/main/resources/update-checker/killbill-server-update-list.properties
@@ -0,0 +1,7 @@
+## Top level keys
+# general.notice = This notice should rarely, if ever, be used as everyone will see it
+
+## 0.6.16 -- latest release
+0.6.16.updates =
+0.6.16.notices = This is the latest GA release.
+0.6.16.release-notes = http://kill-bill.org
diff --git a/server/src/main/webapp/WEB-INF/web.xml b/server/src/main/webapp/WEB-INF/web.xml
index 482e6c1..f5fac62 100644
--- a/server/src/main/webapp/WEB-INF/web.xml
+++ b/server/src/main/webapp/WEB-INF/web.xml
@@ -38,7 +38,7 @@
<filter>
<!-- Guice emulates Servlet API with DI -->
<filter-name>guiceFilter</filter-name>
- <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
+ <filter-class>com.ning.billing.server.filters.KillbillGuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>