This guide explains how you can setup the Kill Bill development environment.

Setting up Kill Bill in your development environment

In order to set up Kill Bill in your development environment, there are a couple of things that you need to do like setting up the code in an IDE, configuring the database and building and running the application. This section covers all these steps. By the end of this section, you should have the code set up and the Kill Bill server running in your development environment.

Setting up code in an IDE

You first need to set up the Kill Bill code in an IDE. You can use any IDE of your choice. This section explains setting up the code in Eclipse IDE. You can download the latest version of the Eclipse IDE from here.

Cloning the Repository

The first step is to clone the Kill Bill repository. For this, you need to follow the steps given below:

  1. Start Eclipse.

  2. Go to Git Repository view (Click on Window > Show View > Other > Git Repositories).

  3. Click on Clone a Git Repository and add the clone to this view.

  4. In the Git Repository details, enter the Kill Bill Git URL https://github.com/killbill/killbill in the URI field.

    1. If you have Git credentials, you can select https in the Protocol dropdown and enter your Git credentials in the User/Password fields.

    2. If you do not have Git credentials , you can Select Git in the Protocol Dropdown. This disables the credentials fields.

    3. Click Next.

  5. In the branch selection view, select the branch named master (By default, all the branches appear selected, you need to uncheck all branches except for master). Click Next.

  6. Select the path on your computer where you would like to clone the code. This path will be referred to as PROJECT_ROOT from now on). For example, if you choose C:/MyProjects/KillBill, PROJECT_ROOT refers to this path. Click Finish (This starts the cloning process and may take a while depending on your internet speed).

Note
Note: Cloning the repository as specified above gives a read-only access to the repository. If you’d like to make changes to the repository, you need to fork the repository and create a pull request.

Creating an Eclipse Project

Once the repository is cloned, you need to create an Eclipse project. For this, you need to follow the steps given below:

  1. Click on File > Import > Maven > Existing Maven Project. Click Next.

  2. Click Browse. Select the PROJECT_ROOT root directory and click Finish.

  3. Some of the Maven plugins used may not be available to m2e, so you may see errors as follows:

m2e plugin errors
  1. Click Cancel.

  2. Create a file lifecycle-mapping-metadata.xml as follows:

     <?xml version="1.0" encoding="UTF-8"?>
     <lifecycleMappingMetadata>
       <pluginExecutions>
          <pluginExecution>
             <pluginExecutionFilter>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <versionRange>1.4</versionRange>
                <goals>
                   <goal>run</goal>
                </goals>
             </pluginExecutionFilter>
             <action>
                <execute>
                   <runOnConfiguration>true</runOnConfiguration>
                   <runOnIncremental>true</runOnIncremental>
                </execute>
             </action>
          </pluginExecution>
          <pluginExecution>
             <pluginExecutionFilter>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>templating-maven-plugin</artifactId>
                <versionRange>1.0-alpha-3</versionRange>
                <goals>
                   <goal>filter-sources</goal>
                </goals>
             </pluginExecutionFilter>
             <action>
                <execute>
                   <runOnConfiguration>true</runOnConfiguration>
                   <runOnIncremental>true</runOnIncremental>
                </execute>
             </action>
          </pluginExecution>
          <pluginExecution>
             <pluginExecutionFilter>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <versionRange>[1.0,)</versionRange>
                <goals>
                   <goal>add-test-source</goal>
                   <goal>add-resource</goal>
                   <goal>add-test-resource</goal>
                   <goal>maven-version</goal>
                   <goal>add-source</goal>
                   <goal>parse-version</goal>
                </goals>
             </pluginExecutionFilter>
             <action>
                <execute>
                   <runOnConfiguration>true</runOnConfiguration>
                   <runOnIncremental>true</runOnIncremental>
                </execute>
             </action>
          </pluginExecution>
          <pluginExecution>
             <pluginExecutionFilter>
                <groupId>com.hubspot.maven.plugins</groupId>
                <artifactId>dependency-scope-maven-plugin</artifactId>
                <versionRange>0.10</versionRange>
                <goals>
                   <goal>check</goal>
                </goals>
             </pluginExecutionFilter>
             <action>
               <ignore />
             </action>
          </pluginExecution>
          <pluginExecution>
             <pluginExecutionFilter>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <versionRange>3.1.2</versionRange>
                <goals>
                   <goal>analyze-duplicate</goal>
                   <goal>analyze-only</goal>
                </goals>
             </pluginExecutionFilter>
             <action>
                <ignore />
             </action>
          </pluginExecution>
          <pluginExecution>
             <pluginExecutionFilter>
                <groupId>org.basepom.maven</groupId>
                <artifactId>duplicate-finder-maven-plugin</artifactId>
                <versionRange>1.5.0</versionRange>
                <goals>
                   <goal>check</goal>
                </goals>
             </pluginExecutionFilter>
             <action>
                <ignore />
             </action>
          </pluginExecution>
       </pluginExecutions>
    </lifecycleMappingMetadata>
  3. Go to Window > Preferences > Maven > Lifecycle Mappings. Click Browse and select the path of the lifecycle-mapping-metadata.xml file. Click Apply and Close.

  4. Build the project again (In Project Explorer, right-click on killbill > Maven > Update Project, then select OK).

  5. This will get rid of all the build errors. Your Eclipse workspace should look like this:

eclipse workspace

Configuring the Database

Before you can execute the code, you need to configure the Kill Bill database manually. By default Kill Bill expects MySQL, but you can also use PostgreSQL.

MySQL Configuration

In order to configure MySQL, you need to follow the steps given below (These steps can be executed either via the MySQL Command line tool or via MySQLWorkBench):

  1. Create a user corresponding to Kill Bill. You can run the following command:

     create user killbilluser identified by 'password';
  2. Create a database corresponding to Kill Bill. You can run the following command:

        create database killbill;
  3. Select the Kill Bill database created above using the following command:

     use killbill;
  4. Run the Kill Bill DDL here.

  5. Grant privileges to the user created above on the Kill bill database using the following command:

     GRANT ALL ON killbill.* TO 'killbilluser' ;
  6. If you are using PostgreSQL, you can refer to the detailed instructions for PostgreSQL setup in our PostgreSQL Configuration document here.

Once the database configuration is done, you should have a database called killbill with the following tables:

account_email_history
 account_emails
 account_history
 accounts
 audit_log
 blocking_state_history
 blocking_states
 bundle_history
 bundles
 bus_events
 bus_events_history
 bus_ext_events
 bus_ext_events_history
 catalog_override_block_definition
 catalog_override_phase_definition
 catalog_override_phase_usage
 catalog_override_plan_definition
 catalog_override_plan_phase
 catalog_override_tier_block
 catalog_override_tier_definition
 catalog_override_usage_definition
 catalog_override_usage_tier
 custom_field_history
 custom_fields
 invoice_billing_events
 invoice_history
 invoice_item_history
 invoice_items
 invoice_parent_children
 invoice_payment_control_plugin_auto_pay_off
 invoice_payment_history
 invoice_payments
 invoice_tracking_id_history
 invoice_tracking_ids
 invoices
 node_infos
 notifications
 notifications_history
 payment_attempt_history
 payment_attempts
 payment_history
 payment_method_history
 payment_methods
 payment_transaction_history
 payment_transactions
 payments
 roles_permissions
 rolled_up_usage
 service_broadcasts
 sessions
 subscription_event_history
 subscription_events
 subscription_history
 subscriptions
 tag_definition_history
 tag_definitions
 tag_history
 tags
 tenant_broadcasts
 tenant_kvs
 tenants
 user_roles
 users

Build

Once you set up the code and database, the next step is to build the application. Kill Bill is a standard Maven project. In order to build Kill Bill, you need to follow the steps given below:

  1. Ensure that you have Maven 3.5.2 or higher (It can be downloaded from here).

  2. Maven requires JDK. Ensure that you have JDK 11 or higher. (You can download it from here.)

  3. Ensure that the JAVA_HOME environment variable is set to the path of your JDK installation (For example, if JDK is installed at C:\Software\jdk11, you need to set JAVA_HOME to C:\Software\jdk11).

  4. Navigate to PROJECT_ROOT.

  5. Run the following command (The first time you run this, the build will take a considerable amount of time as Maven will download all the dependencies from the internet and cache them in the local repository (~/.m2/repository). Subsequent builds will be faster):

      mvn clean install -DskipTests
  6. Verify that the following is displayed which confirms that the build is successful:

     [INFO] killbill ........................................... SUCCESS [ 17.938 s]
     [INFO] killbill-api ....................................... SUCCESS [ 23.352 s]
     [INFO] killbill-util ...................................... SUCCESS [01:37 min]
     [INFO] killbill-tenant .................................... SUCCESS [ 23.817 s]
     [INFO] killbill-account ................................... SUCCESS [ 21.540 s]
     [INFO] killbill-catalog ................................... SUCCESS [ 44.055 s]
     [INFO] killbill-currency .................................. SUCCESS [ 12.204 s]
     [INFO] killbill-subscription .............................. SUCCESS [ 29.722 s]
     [INFO] killbill-entitlement ............................... SUCCESS [ 26.420 s]
     [INFO] killbill-junction .................................. SUCCESS [ 17.059 s]
     [INFO] killbill-invoice ................................... SUCCESS [ 36.480 s]
     [INFO] killbill-overdue ................................... SUCCESS [ 23.769 s]
     [INFO] killbill-payment ................................... SUCCESS [ 36.311 s]
     [INFO] killbill-beatrix ................................... SUCCESS [ 29.213 s]
     [INFO] killbill-jaxrs ..................................... SUCCESS [ 36.799 s]
     [INFO] killbill-profiles .................................. SUCCESS [  0.357 s]
     [INFO] killbill-profiles-killbill ......................... SUCCESS [ 39.344 s]
     [INFO] killbill-profiles-killpay .......................... SUCCESS [ 25.608 s]
     [INFO] ------------------------------------------------------------------------
     [INFO] BUILD SUCCESS
     [INFO] ------------------------------------------------------------------------
    Note
    Note: The build process creates the Kill Bill war file in the /killbill/profiles/killbill/target directory.

Running the Application (Local Jetty Server)

Once the build is successful, you can run the application in a local Jetty server. This helps to verify that everything is set up correctly. In order to run the application on Jetty, you need to follow the steps given below:

  1. Modify the PROJECT_ROOT/profiles/killbill/src/main/resources/killbill-server.properties. Update the following properties as per your database:

     org.killbill.dao.url=jdbc:mysql://127.0.0.1:3306/killbill
     # For PostgreSQL, use jdbc:postgresql://127.0.0.1:5432/killbill?currentSchema=killbillschema
     org.killbill.dao.user=root
     org.killbill.dao.password=root
     org.killbill.dao.logLevel=DEBUG
     org.killbill.billing.osgi.dao.url=jdbc:mysql://127.0.0.1:3306/killbill
     # For PostgreSQL, use jdbc:postgresql://127.0.0.1:5432/killbill?currentSchema=killbillschema
     org.killbill.billing.osgi.dao.user=root
     org.killbill.billing.osgi.dao.password=root
  2. Naviagate to the PROJECT_ROOT directory.

  3. Start Kill Bill by running the following command (Replace PROJECT_ROOT with your actual project root):

     mvn -Dorg.killbill.server.properties=file:///PROJECT_ROOT/profiles/killbill/src/main/resources/killbill-server.properties -Dlogback.configurationFile=./profiles/killbill/src/main/resources/logback.xml jetty:run
  4. This should display the following:

     [INFO] Started ServerConnector@7de2f9a6{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
     [INFO] Started @95008ms
     [INFO] Started Jetty Server
  5. Open a browser window and type http://localhost:8080. This should display the following page:

    killbill homepage

Running the Application in Tomcat

In order to run the application on Tomcat copy the /killbill/profiles/killbill/target/killbill-profiles-killbill-x.y.z-SNAPSHOT war file (generated after the build process) into your Tomcat directory and follow these instructions.

Customizing Log File Path

The steps above configure the application so that the Kill Bill logs are displayed on the console. You can however customize this to save the logs in a separate log file. In order to set this up, you need to follow the steps given below:

  1. Modify the PROJECT_ROOT/profiles/killbill/src/main/resources/logback.xml. Add the following after the license section:

     <?xml version="1.0" encoding="UTF-8"?>
      <configuration>
       <jmxConfigurator />
       <property name="LOGS_DIR" value="<log_file_path>" />
       <conversionRule conversionWord="maskedMsg" converterClass="org.killbill.billing.server.log.obfuscators.ObfuscatorConverter" />
       <appender name="MAIN" class="ch.qos.logback.core.rolling.RollingFileAppender">
          <file>${LOGS_DIR:-./logs}/killbill.out</file>
          <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
             <!-- rollover daily -->
             <fileNamePattern>${LOGS_DIR:-./logs}/killbill-%d{yyyy-MM-dd}.%i.out.gz</fileNamePattern>
             <maxHistory>3</maxHistory>
             <cleanHistoryOnStart>true</cleanHistoryOnStart>
             <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- or whenever the file size reaches 100MB -->
                <maxFileSize>100MB</maxFileSize>
             </timeBasedFileNamingAndTriggeringPolicy>
          </rollingPolicy>
          <encoder>
             <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', tok='%X{kb.userToken}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
          </encoder>
       </appender>
       <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
          <encoder>
             <!-- See http://jira.qos.ch/browse/LOGBACK-262 -->
             <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', tok='%X{kb.userToken}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
          </encoder>
       </appender>
       <logger name="jdbc" level="OFF" />
       <root level="INFO">
          <appender-ref ref="MAIN" />
       </root>
    </configuration>
  2. Replace <log_file_path> above with the path where you want the logs to be created. For example, if you’d like the logs to be in a directory called c:/logs, you need to replace <log_file_path> with c:/logs.

  3. Restart the application by running the Maven command specified above. Now, the logs will be created at the path specified in the logback.xml file as follows:

      <log_file_path>/killbill.out

Setting up a Breakpoint and Remote Debugging

Sometimes, you may face some issues in running the application. In such cases, it is useful to set up a breakpoint and debug the application. Here is how you can do this:

  1. Create a new environment variable MAVEN_OPTS and set it to -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n

  2. Do the following in Eclipse:

    1. Press Ctrl + Shift + T and locate the file that you would like to debug. For example, if the application fails to start, you would need to debug the DefaultKillbillConfigSource.

    2. If this does not show the source code do the following:

      1. Click Attach Source.

      2. Click on External Location and Navigate to your Maven local repository (~/.m2/repository). Select the jar file corresponding to the file that you want to debug. For the DefaultKillbillConfigSource you need to select /org/kill-bill/billing/killbill-platform-base/0.40.4/killbill-platform-base-0.40.4-sources.jar (At the time of writing, 0.40.4 is the latest version of this jar, however this can change so the exact version might be different for you)

    3. Set up a breakpoint as required. For example, if it is an issue in starting the application, you would need to set up a breakpoint in DefaultKillbillConfigSource.java#L118.

    4. Click Run > Debug Configurations.

    5. Double-click New Remote Java Application.

    6. Enter the name that you would like to give to this debug configuration in the Name field.

    7. Click Apply.

    8. Click Close.

  3. Start the application as explained in the "Running the Application" section above.

  4. Click Run > Debug Configurations and double click the the Debug configuration that you created above.

  5. This runs the application in debug mode. You can also set additional breakpoints as required.

Further Debugging

The Debugging Tips document includes some additional debugging tips for Kill Bill in general. You may also reach out to the Kill Bill mailing list, with the kpm diagnostic output as explained in the Seeking Help section.

Some common errors and their solutions

Build Failure

Sometimes, after building the application, the build may fail with the following errors:

 [INFO] killbill-payment ................................... SUCCESS [01:42 min]
 [INFO] killbill-beatrix ................................... SUCCESS [02:04 min]
 [INFO] killbill-jaxrs ..................................... SUCCESS [01:45 min]
 [INFO] killbill-profiles .................................. SUCCESS [  9.896 s]
 [INFO] killbill-profiles-killbill ......................... FAILURE [02:48 min]
 [INFO] killbill-profiles-killpay .......................... SKIPPED
 [INFO] ------------------------------------------------------------------------
 [INFO] BUILD FAILURE
 [INFO] ------------------------------------------------------------------------
 [INFO] Total time:  26:55 min
 [INFO] Finished at: 2020-11-23T10:46:24+05:30
 [INFO] ------------------------------------------------------------------------
 [ERROR] Failed to execute goal org.apache.rat:apache-rat-plugin:0.13:check (default) on project killbill-profiles-killbill: Too many files with unapproved license: 1 See RAT report in: <PROJECT_ROOT>\profiles\killbill\target\rat.txt -> [Help 1]
 [ERROR]
 [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
 [ERROR] Re-run Maven using the -X switch to enable full debug logging.
 [ERROR]
 [ERROR] For more information about the errors and possible solutions, please read the following articles:
 [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
 [ERROR]
 [ERROR] After correcting the problems, you can resume the build with the command
 [ERROR]   mvn <args> -rf :killbill-profiles-killbill

This error is probably because some file is missing license information. You can build the application using the following command:

mvn clean install -DskipTests -Dcheck.skip-rat=true

Jetty Does Not Start

Sometimes, when you run the application, Jetty may fail to start with the following error:

Failed startup of context o.e.j.m.p.JettyWebAppContext@1fafd0af

In such a case, build the application again using the instructions in the "Build" section above and run the application again.

Application Points to the Default Database

Sometimes, when the application is started, it may not use the database configured in the PROJECT_ROOT/profiles/killbill/src/main/resources/killbill-server.properties. Instead, it may use the default H2 database and cause the following errors:

java.io.IOException: org.h2.jdbc.JdbcSQLNonTransientConnectionException: A file path that is implicitly relative to the current working directory is not allowed in the database URL "jdbc:h2:file:/var/tmp/killbill;MODE=MYSQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE". Use an absolute path, ~/name, ./name, or the baseDir setting instead. [90011-200]
        at org.killbill.commons.embeddeddb.h2.H2EmbeddedDB.refreshTableNames(H2EmbeddedDB.java:114)
        at org.killbill.commons.embeddeddb.h2.H2EmbeddedDB.start(H2EmbeddedDB.java:97)
        at org.killbill.billing.server.modules.EmbeddedDBProvider.initializeEmbeddedDB(EmbeddedDBProvider.java:73)
        at org.killbill.billing.server.modules.EmbeddedDBProvider.get(EmbeddedDBProvider.java:60)
        at org.killbill.billing.server.modules.KillbillServerModule.configureEmbeddedDBs(KillbillServerModule.java:141)
        at org.killbill.billing.server.modules.KillbillPlatformModule.configure(KillbillPlatformModule.java:84)
        at org.killbill.billing.server.modules.KillbillServerModule.configure(KillbillServerModule.java:113)
        at com.google.inject.AbstractModule.configure(AbstractModule.java:61)
        at com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:347)
        at com.google.inject.spi.Elements.getElements(Elements.java:104)
        at com.google.inject.internal.InjectorShell$Builder.build(InjectorShell.java:137)
        at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:105)
        at com.google.inject.Guice.createInjector(Guice.java:87)

This error could be due to one of the following issues:

  1. The path of the PROJECT_ROOT/profiles/killbill/src/main/resources/killbill-server.properties is not specified correctly while starting the application. Ensure that the correct path is specified

  2. While starting the application, the PROJECT_ROOT/profiles/killbill/src/main/resources/killbill-server.properties is specified as file://PROJECT_ROOT/profiles/killbill/src/main/resources/killbill-server.properties. The file protocol requires three slashes, so ensure that it is specified as file:///

  3. The database URL is not specified properly, ensure that the PROJECT_ROOT/profiles/killbill/src/main/resources/killbill-server.properties has the correct database properties as specified in the "Running the Application" section above

Logs Not Created

Sometimes, even after configuring your logback.xml file as specified in the "Customizing Log File Path" section, logs might not be created. This is most probably because your logback.xml is not a valid XML file. Some reasons for an XML file to be invalid are leading spaces, unclosed XML tags. In general, if you are able to open the XML file in a web browser without any errors, your XML file is valid.

SQLException on Startup

Sometimes, even after configuring everything as explained above, the following exception might occur when Kill Bill is started:

Caused by: java.sql.SQLTransientConnectionException: Could not connect to address=(host=127.0.0.1)(port=3306)(type=master) : RSA public key is not available client side (option serverRsaPublicKeyFile not set)
	at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.createException(ExceptionFactory.java:79)
	at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.create(ExceptionFactory.java:153)
	at org.mariadb.jdbc.MariaDbDataSource.getConnection(MariaDbDataSource.java:305)
	at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:364)
	at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:206)
	at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:476)
	at com.zaxxer.hikari.pool.HikariPool.access$100(HikariPool.java:71)
	at com.zaxxer.hikari.pool.HikariPool$PoolEntryCreator.call(HikariPool.java:726)
	at com.zaxxer.hikari.pool.HikariPool$PoolEntryCreator.call(HikariPool.java:712)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

Some later versions of MySQL require requesting a public key from the server. Thus, the database connection string needs to be specified as follows in the PROJECT_ROOT/profiles/killbill/src/main/resources/killbill-server.properties file:

org.killbill.dao.url=jdbc:mysql://127.0.0.1:3306/killbill?allowPublicKeyRetrieval=true&useSSL=false
org.killbill.billing.osgi.dao.url=jdbc:mysql://127.0.0.1:3306/killbill?allowPublicKeyRetrieval=true&useSSL=false

ClassNotFoundException on Startup

Sometimes, even after configuring everything as explained above, the following exception might occur when Kill Bill is started:

Caused by: java.lang.ClassNotFoundException: jar file 'killbill-api-0.53.17.jar' could not be instantiate from file path. Error: C:\Users\<username>\.m2\repository\org\kill-bill\billing\killbill-api\0.53.17\killbill-api-0.53.17.jar (The system cannot find the path specified)
    at org.killbill.billing.lifecycle.ServiceFinder.findClasses (ServiceFinder.java:130)
    at org.killbill.billing.lifecycle.ServiceFinder.initialize (ServiceFinder.java:64)
    at org.killbill.billing.lifecycle.ServiceFinder.<init> (ServiceFinder.java:48)
    at org.killbill.billing.util.glue.IDBISetup.mapperFactoriesToRegister (IDBISetup.java:65)
    at org.killbill.billing.server.modules.KillbillServerModule.configureDao (KillbillServerModule.java:127)
    at org.killbill.billing.server.modules.KillbillPlatformModule.configure (KillbillPlatformModule.java:86)
    at org.killbill.billing.server.modules.KillbillServerModule.configure (KillbillServerModule.java:99)
    at com.google.inject.AbstractModule.configure (AbstractModule.java:61)
    at com.google.inject.spi.Elements$RecordingBinder.install (Elements.java:347)
    at com.google.inject.spi.Elements.getElements (Elements.java:104)
    at com.google.inject.internal.InjectorShell$Builder.build (InjectorShell.java:137)

This error typically occurs on Windows machines and is most probably due to a space being present in the Maven repository path. By default, on Windows, Maven uses the C:\Users\<username>\.m2\ path for the local repository. If there is a space in the <username>, this error can occur. In order to get rid of this error you can change the path of the Maven local repository using the following steps:

  1. Open <MAVEN_HOME>/conf/settings.xml.

  2. Update <localRepository> to the desired path. For example, to create the Maven local repository at the c:/mavenrepo path, you need to specify <localRepository>c:/mavenrepo</localRepository>.

  3. Update the new Maven local repository path in Eclipse by navigating to Window > Preferences > Maven > User Settings. In the Global Settings box, click Browse and select the <MAVEN_HOME>/conf/settings.xml.

  4. Restart the application.

Dependencies

The base pom.xml (org.kill-bill.billing:killbill-oss-parent) defines all of the dependencies required by Kill Bill. If a -SNAPSHOT version is specified (e.g. 0.141.74-SNAPSHOT), this means some dependencies haven’t been released yet and you need to build them locally, before being able to build Kill Bill.

Typically, the following repositories need to be built in order:

Navigating the Kill Bill codebase

It can be quite daunting to start poking around the Kill Bill codebase, as the code is scattered over various repositories. Here is a primer on how to get started.

Core System

The following blog posts can help provide more context on the Kill Bill architecture:

Ecosystem

Date, Time and Timezone

A few general concepts around time in Kill Bill:

  • Kill Bill’s granularity is the day, and as a result the system will not invoice for portions of a day.

  • Each account in Kill Bill has a default timezone and that timezone is used throughout the system to be able to convert a DateTime into a Date into the account Timezone.

  • Kill Bill will internally use UTC for all its Datetime manipulation, but any Date information is interpreted as a Date in the account timezone.

Mysql Date, DateTime, Timestamp

We are only relying on date and datetime which are not sensitive to the MySQL timezone setting:

  • Datetime: Storing a Datetime value into MySQL relies on datetime which is independent of the mysql time_zone. It is stored as a UTC value, and the selected value is always the same, regardless of the MySQL timezone.

  • LocalDate: Storing a LocalDate value into MySQL relies on date which is also independent of the MySQL time_zone.

System Configuration

From an operation point of view, there are different places where timezone may be set:

  1. Server on which Kill Bill runs

  2. JVM setting

  3. Database server

It is required to have Kill Bill runs in UTC for correct serialization of DateTime/LocalDate. Actually, in Java, there is no UTC timezone setting but instead GMT. In a first approximation, we will consider those identical, even though they are not and could lead to some rare issues.

When Kill Bill starts, it will override the default timezone if this one was specified as a system property with something different than GMT. The code will log a WARN message and proceed to do so, to avoid issues later down the road.

REST APIs

Kill Bill APIs that accept dates as an argument will allow for the following:

  • A fully qualified Datetime (a point in time)

  • A Date

If there is a need to convert from a Datetime to a Date, the conversion will occur by specifying the account timezone, so the customer sees the resulting Date in their timezone. This would, for instance, be the case when triggering a future invoice by specifying a target Datetime.

If there is a need to convert from a Date to Datetime, this is obviously more subtle as we can’t infer the additional precision to compute the time. The Date is always interpreted to be a Date as seen by the customer, that is in the account timezone.

The system will use the reference time on the account in such a way that converting back from that fully qualified Datetime using the account timezone would give us back the original Date provided.

Multiple changes in a day

So what happens if a user is making several subscription changes within the same day?

In the default mode, Kill Bill will react to changes immediately and trigger a new invoice for each change, which in turn might result in a charge.

Let’s consider the following case, where there exists 3 monthly plans (Bronze, Silver and Gold), ordered by ascending price:

  • Initially, the customer is invoiced for the Bronze, from january 1st to feb 1st. By default a payment would also be made.

  • On January 1st again, the customer changes its mind and moves to Silver. A new invoice is generated that will credit the full month — including the day of january 1st — and the new plan is now invoiced from january 1st to february 1st and the credit generated is immediately used, so in the end the customer is really only invoiced for the difference of the price between the 2 plans; Additionally, a new payment is made for that amount.

  • If now the customer changes its plan on Jan 2nd, the portion from January 1st to January 2nd will be invoiced for the Silver plan and the portion from January 2nd to February 1st will be invoiced for the Gold plan.

From an entitlement point of view, the system will reflect the current plan and therefore two different calls to retrieve the plan information on January 1st may lead to different results since there was a change of plan during that day.