/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF 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 org.jooby; import static java.util.Objects.requireNonNull; import java.util.Map; import java.util.Optional; import java.util.function.Function; import org.jooby.internal.handlers.FlashScopeHandler; import org.jooby.mvc.Flash; import com.google.inject.Binder; import com.typesafe.config.Config; /** * <h1>flash scope</h1> * <p> * The flash scope is designed to transport success and error messages, between requests. The flash * scope is similar to {@link Session} but lifecycle is shorter: data are kept for only one request. * </p> * <p> * The flash scope is implemented as client side cookie, so it helps to keep application stateless. * </p> * * <h2>usage</h2> * * <pre>{@code * { * use(new FlashScope()); * * get("/", req -> { * return req.ifFlash("success").orElse("Welcome!"); * }); * * post("/", req -> { * req.flash("success", "The item has been created"); * return Results.redirect("/"); * }); * } * }</pre> * * {@link FlashScope} is also available on mvc routes via {@link Flash} annotation: * * <pre>{@code * @Path("/") * public class Controller { * * @GET * public Object flashScope(@Flash Map<String, String> flash) { * ... * } * * @GET * public Object flashAttr(@Flash String foo) { * ... * } * * @GET * public Object optionlFlashAttr(@Flash Optional<String> foo) { * ... * } * } * }</pre> * * <p> * Worth to mention that flash attributes are accessible from template engine by prefixing * attributes with <code>flash.</code>. Here is a <code>handlebars.java</code> example: * </p> * * <pre>{@code * {{#if flash.success}} * {{flash.success}} * {{else}} * Welcome! * {{/if}} * }</pre> * * @author edgar * @since 1.0.0.CR4 */ public class FlashScope implements Jooby.Module { public static final String NAME = "flash"; private Function<String, Map<String, String>> decoder = Cookie.URL_DECODER; private Function<Map<String, String>, String> encoder = Cookie.URL_ENCODER; private Optional<Cookie.Definition> cookie = Optional.empty(); private String method = "*"; private String path = "*"; /** * Creates a new {@link FlashScope} and customize the flash cookie. * * @param cookie Cookie template for flash scope. */ public FlashScope(final Cookie.Definition cookie) { this.cookie = Optional.of(requireNonNull(cookie, "Cookie required.")); } /** * Creates a new {@link FlashScope}. */ public FlashScope() { } @Override public void configure(final Env env, final Config conf, final Binder binder) { Config $cookie = conf.getConfig("flash.cookie"); String cpath = $cookie.getString("path"); boolean chttp = $cookie.getBoolean("httpOnly"); boolean csecure = $cookie.getBoolean("secure"); Cookie.Definition cookie = this.cookie .orElseGet(() -> new Cookie.Definition($cookie.getString("name"))); // uses user provided or fallback to defaults cookie.path(cookie.path().orElse(cpath)) .httpOnly(cookie.httpOnly().orElse(chttp)) .secure(cookie.secure().orElse(csecure)); env.router() .use(method, path, new FlashScopeHandler(cookie, decoder, encoder)) .name("flash-scope"); } }