Coder Social home page Coder Social logo

bootique / bootique Goto Github PK

View Code? Open in Web Editor NEW
1.4K 141.0 284.0 2.92 MB

Bootique is a minimally opinionated platform for modern runnable Java apps.

Home Page: https://bootique.io

License: Apache License 2.0

Java 99.96% HTML 0.04%
bootique java runnable-jar dependency-injection

bootique's Introduction

build test deploy Maven Central

Bootique is a minimally opinionated java launcher and integration technology. It is intended for building container-less runnable Java applications. With Bootique you can create REST services, webapps, jobs, DB migration tasks, etc. and run them as if they were simple commands. No JavaEE container required! Among other things Bootique is an ideal platform for Java microservices, as it allows you to create a fully-functional app with minimal setup.

Each Bootique app is a collection of modules interacting with each other via dependency injection. This GitHub project provides Bootique core. Bootique team also develops a number of important modules. A full list is available here.

Quick Links

Support

You have two options:

  • Open an issue on GitHub with a label of "help wanted" or "question" (or "bug" if you think you found a bug).
  • Post a question on the Bootique forum.

TL;DR

For the impatient, here is how to get started with Bootique:

  • Declare the official module collection:
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.bootique.bom</groupId>
            <artifactId>bootique-bom</artifactId>
            <version>3.0-M4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency> 
    </dependencies>
</dependencyManagement>
  • Include the modules that you need:
<dependencies>
    <dependency>
        <groupId>io.bootique.jersey</groupId>
        <artifactId>bootique-jersey</artifactId>
    </dependency>
    <dependency>
        <groupId>io.bootique.logback</groupId>
        <artifactId>bootique-logback</artifactId>
    </dependency>
</dependencies>
  • Write your app:
package com.foo;

import io.bootique.Bootique;

public class Application {
    public static void main(String[] args) {
        Bootique
            .app(args)
            .autoLoadModules()
            .exec()
            .exit();
    }
}

It has main() method, so you can run it!

For a more detailed tutorial proceed to this link.

Upgrading

See the "maven-central" badge above for the current production version of bootique-bom. When upgrading, don't forget to check upgrade notes specific to your version.

bootique's People

Contributors

0xflotus avatar aarrsseni avatar andrus avatar atomashpolskiy avatar bob-obringer avatar const1993 avatar dmitars avatar elena-bondareva avatar irus avatar kravchenkoas avatar lcottereau avatar orischwartz avatar rvs-fluid-it avatar stariy95 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bootique's Issues

BQDaemonTestRuntime to track outcome

Sometimes a daemon app running in background needs to finish before we can test it. In this case instead of waiting for startup, we need to wait till the app stops. To achieve that BQDaemonTestRuntime will need to store an outcome in an optional ivar, and BQDaemonTestFactory.Builder needs a new method startupAndWaitCheck. Note that this is a breaking change, since "startupCheck" changes from Function<BQRuntime, Boolean> to Function<BQDaemonTestRuntime, Boolean>.

UPGRADE NOTES:

If you are using a custom "startupCheck" in your tests, change the function signature to Function<BQDaemonTestRuntime, Boolean>, and use BQDaemonTestRuntime.getRuntime() to access BQRuntime.

Batch POST request doesn't create records in the order they are submitted in

A POST request to an endpoint that performs a syncAndSelect() does not create records in the same order they are submitted (for auto incremented ids).

Does this actually matter?

@rzen mentioned that there was a related issue in the past that would return data out of order for that POST request, which appears to be working... but the IDs are not in order so subsequent GET requests do not return the data in that order. See the example below:

Does this actually matter?

Request

POST /person/ HTTP/1.1
Host: 127.0.0.1:8187
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: b9040f0c-6488-f542-108f-0492559cbd0a

[
    {"firstName":"Bob","lastName":"One"},
    {"firstName":"John","lastName":"Two"},
    {"firstName":"Steven","lastName":"Three"}
]

Response

{
    "data": [
        {
            "id": 200,
            "firstName": "Bob",
            "lastName": "One"
        },
        {
            "id": 202,
            "firstName": "John",
            "lastName": "Two"
        },
        {
            "id": 201,
            "firstName": "Steven",
            "lastName": "Three"
        }
    ],
    "total": 3
}

BQSubpocessTestRuntime: a way to run Bootique test as a subprocess

Sometimes it is not enough to run a unit test "app" in a separate thread via BQDaemonTestRuntime. Instead a full subprocess is required. E.g. we can't test bootique/bootique-logback#10 properly (see TODO in bootique-logback LogbackContextFactory), as Logback initializer initializes statically so we can't test both BQ-configured Logback and XML-configured one in the same set of tests.

So need a BQSubpocessTestRuntime that would fire up a subprocess that we can shut down at the end of the test. Since this will be a Java subprocess, it will need to reuse the same JVM that started the test, as well as the classpath.

Code: Text is larger than text box

Environment:
Android 4.4.4 Chrome v48
iPhone 6 iOS 8.1
iPad iOS 9.2.1 Chrome 48.0, Safari

Steps:
Get Started and Documentation pages - 1.png is attached.

1

Support for metrics

Integrate Dropwizard metrics library into Bootique. Looks like this will have to be one of the few core services that won't be easy to swap out, with downstream modules depending on it. The library looks pretty thorough and it would be a shame if we had to redo it from scratch or wrap into Bootique's own API.

ResourceFactory: Configuration type for abstract resource

Many of BQ configurations across the modules take a String identifying a resource (a config file, etc.) that is resolved as follows:

  1. as URL
  2. as classpath: URL
  3. as absolute or relative file path.

We need to encapsulate configuring, validating and resolving this type of identifiers in a value object that can be reused across modules and in user custom code. E.g.:

class ResourceFactory {
   private String pathOrUrl;

   public URL getUrl() {}
}

will need deserialized for Jackson to be able to create this object from String.

BQTestRuntime.run(..) method

BQTestRuntime can be used top run a command or to poke inside DI container. The first scenario is currently not addressed directly. The user needs to use the runner from BQRuntime. Let's create a shortcut method that also shuts down runtime after invocation.

Guice scope for BQRuntime

Let's introduce an explicit Bootique Runtime Scope to the framework. Per #10 this will be needed for shutdown functionality. And generally feels like a useful abstraction. We may need to rename current BQRuntime class to BQRuntimeScope (making it a Scope) and use the name @BQRuntime for the scope annotation.

BeanValidation for factories

Consider using JSR-349 (Bean Validation) for service factories loaded via ConfigurationFactory. Would be nice to declare property value expectations explicitly.

Service shutdown functionality

While we do not care much about hot redeploys in Bootique, it seems like the right thing to do to provide shutdown events and the ability for the service to cleanup at the end of its scope.

Implementation will lean on #11

Service/Module override support

We need to design a mechanism for overriding core and module-provided services from other modules or the app. Our initial approach of avoiding Guice-level overrides in favor of swapping whole Modules proved unworkable, since Guice does not support inheritance of @provides Module methods. Now looking at Guice explicit override constructs in Modules class

Command dispatch mechanism based on Cli state

Cli object now has a commandName method initialized from command line data in one way or another based on a strategy currently in effect (at the moment the only strategy is JoptCliProvider that calculates the name by matching command names against options). DefaultRunner should use this information in command dispatch.

We'll need to reimplement DefaultRunner as "at most one command" invocation strategy using Cli.commandName() to find the command. Note that this (and JoptCliProvider behavior implemented per #17 and #18) would explicitly disallow multiple matching commands. There will be another jira with a solution for that.

Auto-load extensions

Next step after refactoring modules per #1, is auto-loading them using Java ServiceLoader mechanism. A Module .jar (if it decides to support auto-loading), would declare a bundle class in META-INF/services/com.nhl.bootique.BQModuleProvider . Since auto-loading can result in potentially undeterministic behavior, it will have to be explicitly enabled on app startup:

Bootique.app(args).autoLoadExtensions().run();

This will load all bundles present on class-path into DI container

Separate a concept of DI-bound option from Command

Currently we have a thing called ConfigCommand, which is not a Bootique Command (its "run(..)" is a noop), and it exists purely to contribute a --config flag to the CLI. Instead this task is to provide a DI-managed set of options (similar to Set that we already have), whose purpose is to enable a set of Cli options whose argument values can e.g. be read by services that need to configure themselves.

ConfigHelpCommand: Help for configs

Would be nice to be able to print out help explaining configuration options of an app and all its modules. Something along the lines of :

java --jar myapp.jar --help-config

MODULES
	jdbc: Provides a map of DataSources to your application.
	liquibase
	logback: Integrates Logback framework in your application.

CONFIGURATIONS
	# Root configuration of JDBC module
	jdbc:
		# An arbitrarily named DataSource
		[custom_name]:
			# Minimal number of connections supported by the DataSource
			minConnections: [int]

	# Root configuration for LogbackModule.
	log:
	  appenders:
	    - [appender-type1]
	    - [appender-type2]

This metadata will need to come from somewhere, so we'll use a combination of reflection and explicit property annotations. A module (or BQModuleProvider) will need to explicitly declare all its configurable factories.

FactoryConfigurationService - support for loading parameterized types

Would be nice to be able to load "factories" of type Map<K,V>, etc. Eyeing a simple implementation per http://stackoverflow.com/questions/2525042/how-to-convert-a-json-string-to-a-mapstring-string-with-jackson-json :

<T> T factory(TypeReference<?> type, String prefix);

TODO for the future:

  1. Hide Jackson TypeReference class from our public API
  2. With the ability to return maps, lists and other general purpose classes, calling these methods "factory", and the service itself FactoryConfigurationService is misleading. Need to rename to simply ConfigurationService (with deprecation to avoid upgrade of every single BQ module)

Bootique "bom"

Create a POM "bill of materials" (bom) for bootique and all standard extensions (see "import scope" here). Any given combination can be tested and should be much more reliable then letting the user pick versions by hand.

Redoing test framework for better reuse

The first version was limited to TestRules that are factories. Not very convenient for apps that have a single stack. Instead we should allow to use as TestRules factories, individual stacks and daemon versions of both (a total of 4 combinations). So going to create these rule classes:

BQJUnitApp
BQJUnitAppFactory
BQJUnitDaemon
BQJUnitDaemonFactory

This is a breaking change!!

A test module to write Bootique apps for unit tests

I'd like a facility to start Bootique apps (or collections of modules) inside unit tests. I already wrote a few of those across the modules. Would be nice to have a centralized version. So will create a new module here called "bootique-test" that will provide API for this. I can see 2 cases of such test apps:

  • commands
  • daemons

Allow configuration of available commands in main()

Per #17, #18 and #19 now only one Command can be triggered via options. Let's allow users to suppress plugin-originated commands, and write custom commands that may delegate to other commands (thus customizing or chaining plugin commands).

While we are at it, we might change the final command injection to Map<String, Command> from Set<Command>, already guaranteeing name uniqueness.

Merge bundles and modules into a single concept

Separation of module bootstrap into informal "bundles" and Guice Modules (produced by bundles) seems counterproductive. A Module itself can act as a builder to accept code-based configuration. No need for an extra concept. So changing current bundles into Modules, and also adding new API to Bootique to register Modules by class name:

Bootique.app(args).modules(M1.class, M2.class).run();

FactoryConfigurationService refactoring

Addressing a few abstraction leaks in FactoryConfigurationService:

  1. With the ability to return maps, lists and other general purpose classes, we should no longer use "Factory" in the service name or the method names. Let's rename to ConfigurationService and config.
  2. Hide Jackson TypeReference class from the public API

I guess it is important to keep the old API around (with deprecation), as otherwise we'd have to re-release all extensions.

BQTestRuntime: allow to run and stop produced runtime

Since 0.16, BQTestRuntime.run() no longer shuts down the runtime when finished. This is correct behavior (run and stop are two independent activities). However it creates extra hassle when using BQTestRuntime. E.g. in Logback tests we need to explicitly stop after run to ensure logs are flushed to disk. Much more code than really needed. So need some API like runAndStop maybe that combine the two actions?

Better Module override API

One of the (intentionally?) weak spots in Guice is the service override API. In Bootique it is not uncommon to replace standard services with customized versions, and the current API allows to do that, though it is a multistep process:

Bootique.app(args).override(BQCoreModule.class).with(M1.class)

Perhaps we can create a shortcut using another existing API - BQModuleProvider:

BQModuleProvider p = SomeBuilder.abc().xyz().build();
Bootique.app(args).module(p);

The example above shows how a builder for some service produces a BQModuleProvider, which is then added to Bootique via a new 'module' method. BQModuleProvider contains info on overrides, so it doesn't have to be specified explicitly.

Create maven archetype for Bootique module and app projects

Been creating new modules all week, breaking a bigger project to smaller parts. What would've helped is a template for a typical module project:

pom.xml # containing latest BOM
src/main/java/com/foo/MyModule.java
src/main/java/com/foo/MyModuleProvider.java
src/main/resources/META-INF/services/com.nhl.bootique.BQModuleProvider 
src/test/java/com/foo/MyModuleProviderTest,java  # standard unit test for ServiceProvider bindings

Something similar for the app with the Main class.

Not sure if maven-archetype-plugin is the best way to go here, or we need a custom bq command...

Support for manual management of Commands coming out of Modules

Currently a Bootique app exposes in CLI all commands coming from all its included modules. It works fine in most cases, but has some limitations:

  • Only one command can be executed at a time. If multiple command flags were supplied, one of them is chosen semi-randomly. Combining multiple commands is not possible (e.g. UpdateCommand from bootique-liquibase followed by ServerCommand from bootique-jetty)
  • Fine-tuning your user-visible CLI is not possible (e.g. hiding some Module commands from CLI, using Module as a library, and providing your own commands).

We need a straightforward API for more advanced management of the command set. Set<Command> is injected into OptionsProvider and DefaultRunner. Perhaps we should introduce a second Set collection injected into those services, that is a result of filtering the original set with all module contributions. Then we can have a pluggable filtering service that produces the second set from the first. Then we can add some simple API to Bootique class to manage this, e.g. exclude all module-contributed commands, etc.

Also there should be a way to order and chain commands (setting CommandOutcome.shouldExit to false should help with chaining; what about ordering?)

Start publishing Bootique to Maven central repo

No reason why we shouldn't start publishing Bootique to Maven central. Will need to start with publishing the common parent, and then probably re-release all standard modules to make it easy for the end users.

Map known exceptions to CommandOutcomes

To make Bootique apps more user-friendly, we need to analyze the exceptions caught at the top level in the main thread, and replace known ones with CommandOutcomes that generate clear console messages instead of deep stack traces.

Case 1: Eager dependency init on help Fixable via lazy dependency resolution.

A very common case of exception when commands inject dependencies directly. E.g.:

// often blows up
@Inject
SeverRuntime cayenne;

vs.

// works fine
@Inject
Provider<SeverRuntime> cayenne;

E.g. if you run help command without YAML config , the former will blow up with a very cryptic exception. Confuses me every time. The later works fine and is a great lazy init strategy. How do we catch the former and present to the user in a friendly way?

Case 2: Config file is not found.

Case 3: More than one command invoked.

Currently generates java.lang.RuntimeException: Ambiguous options, matched multiple commands: x, y exception wrapped in Guice CreationException. See #140

Create BootLogger outside DI, add "trace" logging

We need to be able to log the boot sequence in the absence of DI container (besides container does not guarantee a logger to be present). So creating BootLogger outside DI (binding that instance to DI).

Additionally adding a trace method for conditional logging of low-level Bootique events during the boot sequence. Trace will be enabled if -Dbq.trace property is present (no need to set a value for the property. No value still enables tracing).

A wrapper for BQTestRuntime injectable to JUnit

Create a BQTestFactory as a wrapper for BQTestRuntime that can be used within unit tests to test configurations, etc. E.g.:

public class MyTest {

  @Rule
  public BQTestFactory testFactory = new BQTestFactory();

  @Test
  public void testMe() {
     ConfigurationFactory f = 
          testFactory.newRuntime().build("--config=src/test/resources/test.yml");
     MyFactory myF = f.config(MyFactory.class, "xx");
     ...
  }
}

BQDaemonTestRuntime doesn't log startup failures

SERVER_APP = new BQDaemonTestRuntime(configurator, r -> r.getInstance(Server.class).isStarted());
SERVER_APP.start(5, TimeUnit.SECONDS, "--server", "--config=test.yml");

When another server runs on port 8080, test server just doesn't start, without much information useful to the developer.

CliStyle: a strategy for customizing command-line style

One of the benefits of Bootique is its flexibility in regards to the core framework services. Let's start taking advantage of that and provide various styles of command to option binding for different types of apps. We can provide the following styles out of the box:

  • CommandsAsOptionsStyle - current strategy. Commands are bound to certain options. If an option is present, command is executed.
  • CommandAsFirstArgStyle - command is determined from the first non-option argument.
  • ImplicitCommandStyle - only 2 commands are available - specified custom command and help. Custom command is invoked by default. Help - when explicit --help flag is provided.

ImplicitCommandStyle is useful for writing single-purpose intuitive command-line tools. CommandAsFirstArgStyle is a Git-style app where a single binary supports multiple commands with their own options.

Support for configs polymorphism

Jackson supports polymorphic type resolution for configuration based on a value of a specific property in YAML (e.g. type: mytype). A supertype (or interface) is annotated with @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "xyz") and concrete subclasses - with @JsonTypeName("abc"). This is great for dynamic configurations where each possible subclass has different set of properties. (E.g. FileAppender vs. ConsoleAppender).

Current workaround is to use Map<String, String> and manually binding properties.

BQDaemonTestRuntime NPE in stop if there was an error in start

If the BQDaemonTestRuntime failed to start for any reason, stop() may still be called in the unit test. In this case the runtime is adding to the noise by throwing an extra exception:

java.lang.NullPointerException
    at com.nhl.bootique.test.BQDaemonTestRuntime.stop(BQDaemonTestRuntime.java:80)
    at com.foo.MyIT.stopJetty(MyIT.java:72)

need to check for null...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.