jooby-project / jooby Goto Github PK
View Code? Open in Web Editor NEWThe modular web framework for Java and Kotlin
Home Page: https://jooby.io
License: Apache License 2.0
The modular web framework for Java and Kotlin
Home Page: https://jooby.io
License: Apache License 2.0
Today, it is possible to access to path params, but not req params. It might be useful to allow initial req params
A jooby app should be able to be packaged as a WAR file. This will allow a jobby app to be deployed into a Servlet Container.
War generation will be done by the maven assembly plugin.
Integrate with Jdbi:
Basic usage:
{
use(new Jdbi());
get("/", req {@literal ->} {
DBI dbi = req.require(DBI.class);
// ... work with dbi
});
get("/handle", req {@literal ->} {
try (Handle handle = req.require(Handle.class)) {
// ... work with dbi handle
}
});
}
Jdbi module require/extends https://github.com/jooby-project/jooby/tree/master/jooby-jdbc
hotswap will be done at JVM level with: http://dcevm.github.io/
A java agent it's require to "restart" some statically binded services (like routes, ORM mappings, etc.)
A good alternative for the custom agent could be: https://github.com/HotswapProjects/HotswapAgent
the following properties allow to setup/configure jetty thread pool:
jetty.threads.min=10
jetty.threads.max=200
jetty.threads.timeout=60000
Implementation of request scoped objects get tricky if we using a child injector per request...
Starting from 0.5.0 Request.Module
will be replaced by a RequestScoped
annotation (like the servlet module from Guice). But keep in mind jooby won't depends on servlet-module because that will introduce a transitive dependency to the Servlet API.
useful if grunt (or similar tools) is required in dev environment (development).
<plugin>
<groupId>org.jooby</groupId>
<artifactId>jooby-maven-plugin</artifactId>
<configuration>
<commands>
<command>
<name>npm</name>
<arguments>
<argmuent>install</argmuent>
</arguments>
</command>
<command>
<name>grunt</name>
<arguments>
<argmuent>local</argmuent>
</arguments>
<wait>false</wait>
</command>
</commands>
</configuration>
</plugin>
A call to: mvn jooby:run
will:
npm install
(blocking, wait = true)grunt local
(no blocking, wait = false)Commands section is optional but when present commands will be executed before the jooby app in the order they were provided
It should be possible to import/reuse routes from an existing App, for example:
public class A extends Jooby {
{
get("/a/1", req -> ...);
}
}
public class B extends Jooby {
{
get("/b/1", req -> ...);
}
}
public class App extends Jooby {
{
use(new A());
use(new B());
}
}
App.java contains all the routes from A and B. Also, ONLY routes are imported (modules, parser, formatter, etc.. will be ignored)
ERROR [2014-11-27 11:11:58,264] execution resulted in serious error
java.lang.NullPointerException: A reason is required.
at java.util.Objects.requireNonNull(Objects.java:228) ~[na:1.8.0]
at org.jooby.WebSocket$CloseStatus.of(WebSocket.java:160) ~[classes/:na]
at org.jooby.internal.jetty.JettyWebSocketHandler.onWebSocketClose(JettyWebSocketHandler.java:84) ~[classes/:na]
at org.eclipse.jetty.websocket.common.events.JettyListenerEventDriver.onClose(JettyListenerEventDriver.java:79) [websocket-common-9.2.5.v20141112.jar:9.2.5.v20141112]
at org.eclipse.jetty.websocket.common.WebSocketSession.notifyClose(WebSocketSession.java:342) [websocket-common-9.2.5.v20141112.jar:9.2.5.v20141112]
at org.eclipse.jetty.websocket.common.WebSocketSession.onConnectionStateChange(WebSocketSession.java:374) [websocket-common-9.2.5.v20141112.jar:9.2.5.v20141112]
at org.eclipse.jetty.websocket.common.io.IOState.notifyStateListeners(IOState.java:185) [websocket-common-9.2.5.v20141112.jar:9.2.5.v20141112]
support capturing groups on path vars (a.k.a index var)
get("/assets/**", req -> req.vars().get(0)); // /assets/js/jquery.js -> js/jquery.js
get("/:key/:value", req -> req.vars().get(0) + req.vars().get(1)); // /foo/var -> foo:bar
org.jooby.Body.Writer
must provides access to request locals (request attributes).
A good example is to allow access to config properties at the rendering phase:
{
get("*", (req, rsp) -> req.set("config", req.require(Config.class)));
}
Later at rendering stage, we can:
{{config.someProperty}}
<dependency>
<groupId>com.ning</groupId>
<artifactId>async-http-client</artifactId>
</dependency>
vs
<dependency>
<groupId>com.ning</groupId>
<artifactId>async-http-client</artifactId>
<scope>test</scope>
</dependency>
Introduce a new contract for dealing with param conversions:
interface ParamConverter {
Object convert(TypeLiteral<?> type, Object[] values, Context ctx);
}
Convert method will be executed every time we try to access a request parameter (either from explicit API or from a MVC handler):
get("/", req -> {
T value = req.param("myparam").to(T.class);
}
There will be built-in converters for primitives, strings, dates, enums, collections and optionals, but also classes with a public string constructor and/or static methods named: valueOf, fromString, fromName.
Any other new type must be done with a custom param converter:
{
param((type, values, ctx) -> {
if (type.getRawType() == T.class) {
// convert a raw value to T
return ...;
}
// no luck! ask next converter in the chain
return ctx.convert(type, values);
});
}
Param converter are executed in the order they were registered. The first param converter that matches/resolved a type wins.
Today a view model can be anything:
get("/", View.of("view-name", new Model());
From now on, it must be a Map
get("/", () -> View.of("view-name", "model", new Model());
// or
get("/", () -> {
Map<String, Object> model = new HashMap<>():
model.put("model", model);
return View.of("view-name", model);
});
a common example is to have a create/update handler where the id is optional for create and present for update, something like:
post("/model", "/model/:id", req -> {
Optional<String> id = req.param("id").toOptional(String.class);
...
});
In addition org.jooby.mvc.Path
should support multiples patterns too:
@Path({"/model", "/model/:id"})
@GET
public Object createORUpdate(Optional<String> id) {
...
}
script will be under etc/bin
dir. The scripts are going to be processed by zip distribution #9
This issue is related to #32. From request object it should be possible to seed a RequestScoped object:
user("*", req -> {
req.set(Type.class, new Type());
}
seed method(s) looks like:
Request set(final Class<?> type, final Object value);
Request set(final TypeLiteral<?> type, final Object value);
Request set(Key<?> key, Object value);
{
use(new Ftl());
get("/", req -> View.of("index", "model", new MyModel());
}
There is a bug while starting two db connection from the jdbc-module.
db = mem
db.audit = mem
The two properties collide each other and the db = mem
value is lost.
The correct way of defining two databases will be:
db.main = mem
db.audit = mem
with the following java code:
{
use(new Jdbc("db.main"));
use(new Jdbc("db.audit"));
}
motivation:
There are some benchmarks too: http://www.techempower.com/benchmarks/ where undertow seems to perform better than Jetty. Those benchmarks are not the main reason of choosing undertow (reasons were described before). Jetty is a high performance server too.
With the addition of #44 it is pretty straightforward to use http://www.webjars.org/:
assets("/js/**", "/META-INF/resources/webjars/{0}");
GET /js/jquery/2.1.3/jquery.js
Short/custom mapping:
assets("/js/lib/*-*.js", "/META-INF/resources/webjars/{0}/{1}/{0}.js");
GET /js/lib/jquery-2.1.3.js
rename some methods of Mutant
:
req.param("name").stringValue() will be req.param("name").value()
req.param("name").enumValue() will be req.param("name").toEnum(...)
It'd be nice that when you run mvn jooby:run it printed something like:
Listening on: http://127.0.0.1:8080
That way if you have a console that parses output it becomes clickable and you avoid having to type the url in the browser manually.
Today, they belong to current response. From now on, they should be available in the request
These properties should be present in any request by default:
these two vars must be saved as request locals:
assertEquals(req.path(), req.get("path"));
assertEquals(req.require(Config.class).getString("application.path"), req.get("application.path"));
The application.path property control the default context path of the app, but today it doesn't work
In addition to the fat jar distribution, a zip with the following structure should be created too:
public/
config/
logs/
tmp/
start.sh
stop.sh
myapp.jar
Zip distribution should be created with Maven, while executing: mvn clean package
Before:
get("/", () -> Body.ok());
After:
get("/", () -> Results.ok());
Result sounds and feel better
application.host property should default to: 0.0.0.0
Json.configure method will be renamed to Json.doWith. This is the jackson-module
Configurer callback should have access to current config
These two value resolver will give you access to com.typesafe.config.Config
and org.jooby.Locals
from handlebars templates.
See #26 for more details
Actual implementation let undertow to set content-length or transfer-encoding: chunked header on static resources. The asset handler should attempt to always set the content-length in order to improve response time performance
start.sh MUST set the -Dapplication.env=$APP_ENV
property
Once #34 get done it should be pretty easy to add a new web server, like http://netty.io/
add a mongodb module using the mongodb Java Driver and the Morphia library
application.conf
db=db = "mongodb://localhost/mydb"
MyApp.java
{
use(new MongoDB());
get("/list", req ->
req.require(Datastore.class).find(MyObject.class).asList();
);
}
Module must provide the following services: Datastore, Morphia and MongoClient.
The db
property is used to create a MongoClient.
A web server should be pluggable so in the future Jooby can be package as war and be deployed into a Server Container.
This also will allow to provide multiples server implementation (undertow, netty, jetty, servlets) and let people to choose the best for them
given:
public class Mvc {
@GET
@Path("/")
public Object handle(Optional<String> value) {
return value.orElseThrow(()-> new Err(Status.BAD_REQUEST));
}
}
expected output when value is missing is 400 (bad request) but I got 500 (server error). This only occurs on MVC routes.
let handlebars helper to be injected by Guice:
{
use(new Hbs().with(Helpers.class));
}
public class Helpers {
@Inject
public Helpers(A a) {
this.a = a;
}
public String myHelper() {
return a.something();
}
}
Please note isn't require to inject a Helper, simple/small helper can be created easily with the configurer callback:
{
use(new Hbs().doWith((hbs, config) -> {
hbs.registerHelper("myhelper", (ctx, options) -> {
return ...;
});
hbs.registerHelpers(Helpers.class);
});
}
req params/headers can be injected in any of these classes:
public interface Person {
String name();
int age();
}
public class Person {
public final String name;
public final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Person {
private String name;
private int age;
public String name() {
return name;
}
public int age() {
return age;
}
}
retrieval is done using the req.body or req.params method:
// POST or PUT
Person person = req.body(Person.class);
// GET, etc.
Person person = req.params(Person.class);
or from MVC method
@GET
public Object params(Person person) {
...
}
@POST
public Object body(Person person) {
...
}
Instances of org.jooby.Managed
will be started/stopped by Jooby. This mean any Guice o
The Managed.start
callback will be executed on every single Guice object, regarless of the scope.
The Manage.stop
callback will be executed on Singleton Guice objects, ONLY.
Alternative, any class method annotated with @PostContruct
and/or PreDestroy
will be supported too.
Integrate and support Quartz Scheduler
HTTP session should work quite similar to: https://github.com/expressjs/session and must not depends on the target web server (jetty, undetown, etc..)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.