BAEL-3059: Update Play Framework (#7674)
* Implementation of Introduction to Play Framework in Java * Implementation of Introduction to Play Framework in Java * Implementation of Introduction to Play Framework in Java * Implementation of the tutorial for Introduction to Play Framework. * Updated code for Play Routing to 2.7.3 * Updated code for Play Routing to 2.7.3 * Initial Commit * Added request object to create end point * Finished implementing student-api * Finished implementing student-api * Implementation of the tutorial for Introduction to Play Framework. * Updated test names * Removed Lombok dependency * Corrected isSuccessful spelling and removed the +1 on student ids
This commit is contained in:
parent
0d648321dc
commit
5bce8b22a1
|
@ -1,6 +1,7 @@
|
||||||
logs
|
logs
|
||||||
target
|
target
|
||||||
/.idea
|
/.idea
|
||||||
|
/.g8
|
||||||
/.idea_modules
|
/.idea_modules
|
||||||
/.classpath
|
/.classpath
|
||||||
/.project
|
/.project
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
This software is licensed under the Apache 2 license, quoted below.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project 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.
|
|
|
@ -1,49 +0,0 @@
|
||||||
This is your new Play application
|
|
||||||
=================================
|
|
||||||
|
|
||||||
This file will be packaged with your application when using `activator dist`.
|
|
||||||
|
|
||||||
There are several demonstration files available in this template.
|
|
||||||
|
|
||||||
Controllers
|
|
||||||
===========
|
|
||||||
|
|
||||||
- HomeController.java:
|
|
||||||
|
|
||||||
Shows how to handle simple HTTP requests.
|
|
||||||
|
|
||||||
- AsyncController.java:
|
|
||||||
|
|
||||||
Shows how to do asynchronous programming when handling a request.
|
|
||||||
|
|
||||||
- CountController.java:
|
|
||||||
|
|
||||||
Shows how to inject a component into a controller and use the component when
|
|
||||||
handling requests.
|
|
||||||
|
|
||||||
Components
|
|
||||||
==========
|
|
||||||
|
|
||||||
- Module.java:
|
|
||||||
|
|
||||||
Shows how to use Guice to bind all the components needed by your application.
|
|
||||||
|
|
||||||
- Counter.java:
|
|
||||||
|
|
||||||
An example of a component that contains state, in this case a simple counter.
|
|
||||||
|
|
||||||
- ApplicationTimer.java:
|
|
||||||
|
|
||||||
An example of a component that starts when the application starts and stops
|
|
||||||
when the application stops.
|
|
||||||
|
|
||||||
Filters
|
|
||||||
=======
|
|
||||||
|
|
||||||
- Filters.java:
|
|
||||||
|
|
||||||
Creates the list of HTTP filters used by your application.
|
|
||||||
|
|
||||||
- ExampleFilter.java
|
|
||||||
|
|
||||||
A simple filter that adds a header to every response.
|
|
|
@ -1,46 +0,0 @@
|
||||||
import javax.inject.*;
|
|
||||||
import play.*;
|
|
||||||
import play.mvc.EssentialFilter;
|
|
||||||
import play.http.HttpFilters;
|
|
||||||
import play.mvc.*;
|
|
||||||
|
|
||||||
import filters.ExampleFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class configures filters that run on every request. This
|
|
||||||
* class is queried by Play to get a list of filters.
|
|
||||||
*
|
|
||||||
* Play will automatically use filters from any class called
|
|
||||||
* <code>Filters</code> that is placed the root package. You can load filters
|
|
||||||
* from a different class by adding a `play.http.filters` setting to
|
|
||||||
* the <code>application.conf</code> configuration file.
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class Filters implements HttpFilters {
|
|
||||||
|
|
||||||
private final Environment env;
|
|
||||||
private final EssentialFilter exampleFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param env Basic environment settings for the current application.
|
|
||||||
* @param exampleFilter A demonstration filter that adds a header to
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
public Filters(Environment env, ExampleFilter exampleFilter) {
|
|
||||||
this.env = env;
|
|
||||||
this.exampleFilter = exampleFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EssentialFilter[] filters() {
|
|
||||||
// Use the example filter if we're running development mode. If
|
|
||||||
// we're running in production or test mode then don't use any
|
|
||||||
// filters at all.
|
|
||||||
if (env.mode().equals(Mode.DEV)) {
|
|
||||||
return new EssentialFilter[] { exampleFilter };
|
|
||||||
} else {
|
|
||||||
return new EssentialFilter[] {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
import com.google.inject.AbstractModule;
|
|
||||||
import java.time.Clock;
|
|
||||||
|
|
||||||
import services.ApplicationTimer;
|
|
||||||
import services.AtomicCounter;
|
|
||||||
import services.Counter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is a Guice module that tells Guice how to bind several
|
|
||||||
* different types. This Guice module is created when the Play
|
|
||||||
* application starts.
|
|
||||||
*
|
|
||||||
* Play will automatically use any class called `Module` that is in
|
|
||||||
* the root package. You can create modules in other locations by
|
|
||||||
* adding `play.modules.enabled` settings to the `application.conf`
|
|
||||||
* configuration file.
|
|
||||||
*/
|
|
||||||
public class Module extends AbstractModule {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configure() {
|
|
||||||
// Use the system clock as the default implementation of Clock
|
|
||||||
bind(Clock.class).toInstance(Clock.systemDefaultZone());
|
|
||||||
// Ask Guice to create an instance of ApplicationTimer when the
|
|
||||||
// application starts.
|
|
||||||
bind(ApplicationTimer.class).asEagerSingleton();
|
|
||||||
// Set AtomicCounter as the implementation for Counter.
|
|
||||||
bind(Counter.class).to(AtomicCounter.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
package controllers;
|
|
||||||
|
|
||||||
import akka.actor.ActorSystem;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
import play.*;
|
|
||||||
import play.mvc.*;
|
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.CompletionStage;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import scala.concurrent.duration.Duration;
|
|
||||||
import scala.concurrent.ExecutionContextExecutor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This controller contains an action that demonstrates how to write
|
|
||||||
* simple asynchronous code in a controller. It uses a timer to
|
|
||||||
* asynchronously delay sending a response for 1 second.
|
|
||||||
*
|
|
||||||
* @param actorSystem We need the {@link ActorSystem}'s
|
|
||||||
* {@link Scheduler} to run code after a delay.
|
|
||||||
* @param exec We need a Java {@link Executor} to apply the result
|
|
||||||
* of the {@link CompletableFuture} and a Scala
|
|
||||||
* {@link ExecutionContext} so we can use the Akka {@link Scheduler}.
|
|
||||||
* An {@link ExecutionContextExecutor} implements both interfaces.
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class AsyncController extends Controller {
|
|
||||||
|
|
||||||
private final ActorSystem actorSystem;
|
|
||||||
private final ExecutionContextExecutor exec;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public AsyncController(ActorSystem actorSystem, ExecutionContextExecutor exec) {
|
|
||||||
this.actorSystem = actorSystem;
|
|
||||||
this.exec = exec;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An action that returns a plain text message after a delay
|
|
||||||
* of 1 second.
|
|
||||||
* <p>
|
|
||||||
* The configuration in the <code>routes</code> file means that this method
|
|
||||||
* will be called when the application receives a <code>GET</code> request with
|
|
||||||
* a path of <code>/message</code>.
|
|
||||||
*/
|
|
||||||
public CompletionStage<Result> message() {
|
|
||||||
return getFutureMessage(1, TimeUnit.SECONDS).thenApplyAsync(Results::ok, exec);
|
|
||||||
}
|
|
||||||
|
|
||||||
private CompletionStage<String> getFutureMessage(long time, TimeUnit timeUnit) {
|
|
||||||
CompletableFuture<String> future = new CompletableFuture<>();
|
|
||||||
actorSystem.scheduler().scheduleOnce(
|
|
||||||
Duration.create(time, timeUnit),
|
|
||||||
() -> future.complete("Hi!"),
|
|
||||||
exec
|
|
||||||
);
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package controllers;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
import play.*;
|
|
||||||
import play.mvc.*;
|
|
||||||
|
|
||||||
import services.Counter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This controller demonstrates how to use dependency injection to
|
|
||||||
* bind a component into a controller class. The class contains an
|
|
||||||
* action that shows an incrementing count to users. The {@link Counter}
|
|
||||||
* object is injected by the Guice dependency injection system.
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class CountController extends Controller {
|
|
||||||
|
|
||||||
private final Counter counter;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public CountController(Counter counter) {
|
|
||||||
this.counter = counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An action that responds with the {@link Counter}'s current
|
|
||||||
* count. The result is plain text. This action is mapped to
|
|
||||||
* <code>GET</code> requests with a path of <code>/count</code>
|
|
||||||
* requests by an entry in the <code>routes</code> config file.
|
|
||||||
*/
|
|
||||||
public Result count() {
|
|
||||||
return ok(Integer.toString(counter.nextCount()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,14 +1,25 @@
|
||||||
package controllers;
|
package controllers;
|
||||||
|
|
||||||
|
import play.libs.concurrent.HttpExecutionContext;
|
||||||
import play.mvc.*;
|
import play.mvc.*;
|
||||||
|
import play.twirl.api.Html;
|
||||||
|
|
||||||
import views.html.*;
|
import javax.inject.Inject;
|
||||||
|
import java.util.concurrent.CompletionStage;
|
||||||
|
|
||||||
|
import static java.util.concurrent.CompletableFuture.supplyAsync;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller contains an action to handle HTTP requests
|
* This controller contains an action to handle HTTP requests
|
||||||
* to the application's home page.
|
* to the application's home page.
|
||||||
*/
|
*/
|
||||||
public class HomeController extends Controller {
|
public class HomeController extends Controller {
|
||||||
|
private HttpExecutionContext ec;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public HomeController(HttpExecutionContext ec) {
|
||||||
|
this.ec = ec;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An action that renders an HTML page with a welcome message.
|
* An action that renders an HTML page with a welcome message.
|
||||||
|
@ -17,7 +28,41 @@ public class HomeController extends Controller {
|
||||||
* <code>GET</code> request with a path of <code>/</code>.
|
* <code>GET</code> request with a path of <code>/</code>.
|
||||||
*/
|
*/
|
||||||
public Result index() {
|
public Result index() {
|
||||||
return ok(index.render("Your new application is ready."));
|
return ok(views.html.index.render());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Result applyHtml() {
|
||||||
|
return ok(Html.apply("<h1>This text will appear as a heading 1</h1>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result badRequestPage() {
|
||||||
|
return badRequest("Your request data has issues.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result notFoundPage() {
|
||||||
|
return notFound("Could not find the page you requested.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result customContentType() {
|
||||||
|
return ok("This is some text content").as("text/html");
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletionStage<Result> asyncOperation() {
|
||||||
|
return supplyAsync(() -> {
|
||||||
|
return longRunningTask();
|
||||||
|
}, ec.current())
|
||||||
|
.thenApplyAsync(s -> {
|
||||||
|
return ok("Got result -> " + s);
|
||||||
|
}, ec.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String longRunningTask() {
|
||||||
|
return "Long running task has completed";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result setHeaders() {
|
||||||
|
return ok("This is some text content")
|
||||||
|
.as("text/html")
|
||||||
|
.withHeader("Header-Key", "Some value");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
package controllers;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import models.Student;
|
|
||||||
import models.StudentStore;
|
|
||||||
import play.libs.Json;
|
|
||||||
import play.mvc.Controller;
|
|
||||||
import play.mvc.Result;
|
|
||||||
import util.Util;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class StudentController extends Controller {
|
|
||||||
public Result create() {
|
|
||||||
JsonNode json = request().body().asJson();
|
|
||||||
if (json == null) {
|
|
||||||
return badRequest(Util.createResponse("Expecting Json data", false));
|
|
||||||
}
|
|
||||||
Student student = StudentStore.getInstance().addStudent(Json.fromJson(json, Student.class));
|
|
||||||
JsonNode jsonObject = Json.toJson(student);
|
|
||||||
return created(Util.createResponse(jsonObject, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result update() {
|
|
||||||
JsonNode json = request().body().asJson();
|
|
||||||
if (json == null) {
|
|
||||||
return badRequest(Util.createResponse("Expecting Json data", false));
|
|
||||||
}
|
|
||||||
Student student = StudentStore.getInstance().updateStudent(Json.fromJson(json, Student.class));
|
|
||||||
if (student == null) {
|
|
||||||
return notFound(Util.createResponse("Student not found", false));
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonNode jsonObject = Json.toJson(student);
|
|
||||||
return ok(Util.createResponse(jsonObject, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result retrieve(int id) {
|
|
||||||
if (StudentStore.getInstance().getStudent(id) == null) {
|
|
||||||
return notFound(Util.createResponse("Student with id:" + id + " not found", false));
|
|
||||||
}
|
|
||||||
JsonNode jsonObjects = Json.toJson(StudentStore.getInstance().getStudent(id));
|
|
||||||
return ok(Util.createResponse(jsonObjects, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result listStudents() {
|
|
||||||
Set<Student> result = StudentStore.getInstance().getAllStudents();
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
|
|
||||||
JsonNode jsonData = mapper.convertValue(result, JsonNode.class);
|
|
||||||
return ok(Util.createResponse(jsonData, true));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result delete(int id) {
|
|
||||||
if (!StudentStore.getInstance().deleteStudent(id)) {
|
|
||||||
return notFound(Util.createResponse("Student with id:" + id + " not found", false));
|
|
||||||
}
|
|
||||||
return ok(Util.createResponse("Student with id:" + id + " deleted", true));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
package filters;
|
|
||||||
|
|
||||||
import akka.stream.Materializer;
|
|
||||||
import java.util.concurrent.CompletionStage;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import javax.inject.*;
|
|
||||||
import play.mvc.*;
|
|
||||||
import play.mvc.Http.RequestHeader;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a simple filter that adds a header to all requests. It's
|
|
||||||
* added to the application's list of filters by the
|
|
||||||
* {@link Filters} class.
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class ExampleFilter extends Filter {
|
|
||||||
|
|
||||||
private final Executor exec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mat This object is needed to handle streaming of requests
|
|
||||||
* and responses.
|
|
||||||
* @param exec This class is needed to execute code asynchronously.
|
|
||||||
* It is used below by the <code>thenAsyncApply</code> method.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
public ExampleFilter(Materializer mat, Executor exec) {
|
|
||||||
super(mat);
|
|
||||||
this.exec = exec;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompletionStage<Result> apply(
|
|
||||||
Function<RequestHeader, CompletionStage<Result>> next,
|
|
||||||
RequestHeader requestHeader) {
|
|
||||||
|
|
||||||
return next.apply(requestHeader).thenApplyAsync(
|
|
||||||
result -> result.withHeader("X-ExampleFilter", "foo"),
|
|
||||||
exec
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package models;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class StudentStore {
|
|
||||||
private static StudentStore instance;
|
|
||||||
private Map<Integer, Student> students = new HashMap<>();
|
|
||||||
|
|
||||||
public static StudentStore getInstance() {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new StudentStore();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Student addStudent(Student student) {
|
|
||||||
int id = students.size();
|
|
||||||
student.setId(id);
|
|
||||||
students.put(id, student);
|
|
||||||
return student;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Student getStudent(int id) {
|
|
||||||
return students.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Student> getAllStudents() {
|
|
||||||
return new HashSet<>(students.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Student updateStudent(Student student) {
|
|
||||||
int id = student.getId();
|
|
||||||
if (students.containsKey(id)) {
|
|
||||||
students.put(id, student);
|
|
||||||
return student;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean deleteStudent(int id) {
|
|
||||||
return students.remove(id) != null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
package services;
|
|
||||||
|
|
||||||
import java.time.Clock;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import javax.inject.*;
|
|
||||||
import play.Logger;
|
|
||||||
import play.inject.ApplicationLifecycle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class demonstrates how to run code when the
|
|
||||||
* application starts and stops. It starts a timer when the
|
|
||||||
* application starts. When the application stops it prints out how
|
|
||||||
* long the application was running for.
|
|
||||||
*
|
|
||||||
* This class is registered for Guice dependency injection in the
|
|
||||||
* {@link Module} class. We want the class to start when the application
|
|
||||||
* starts, so it is registered as an "eager singleton". See the code
|
|
||||||
* in the {@link Module} class to see how this happens.
|
|
||||||
*
|
|
||||||
* This class needs to run code when the server stops. It uses the
|
|
||||||
* application's {@link ApplicationLifecycle} to register a stop hook.
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class ApplicationTimer {
|
|
||||||
|
|
||||||
private final Clock clock;
|
|
||||||
private final ApplicationLifecycle appLifecycle;
|
|
||||||
private final Instant start;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public ApplicationTimer(Clock clock, ApplicationLifecycle appLifecycle) {
|
|
||||||
this.clock = clock;
|
|
||||||
this.appLifecycle = appLifecycle;
|
|
||||||
// This code is called when the application starts.
|
|
||||||
start = clock.instant();
|
|
||||||
Logger.info("ApplicationTimer demo: Starting application at " + start);
|
|
||||||
|
|
||||||
// When the application starts, register a stop hook with the
|
|
||||||
// ApplicationLifecycle object. The code inside the stop hook will
|
|
||||||
// be run when the application stops.
|
|
||||||
appLifecycle.addStopHook(() -> {
|
|
||||||
Instant stop = clock.instant();
|
|
||||||
Long runningTime = stop.getEpochSecond() - start.getEpochSecond();
|
|
||||||
Logger.info("ApplicationTimer demo: Stopping application at " + clock.instant() + " after " + runningTime + "s.");
|
|
||||||
return CompletableFuture.completedFuture(null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package services;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is a concrete implementation of the {@link Counter} trait.
|
|
||||||
* It is configured for Guice dependency injection in the {@link Module}
|
|
||||||
* class.
|
|
||||||
*
|
|
||||||
* This class has a {@link Singleton} annotation because we need to make
|
|
||||||
* sure we only use one counter per application. Without this
|
|
||||||
* annotation we would get a new instance every time a {@link Counter} is
|
|
||||||
* injected.
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class AtomicCounter implements Counter {
|
|
||||||
|
|
||||||
private final AtomicInteger atomicCounter = new AtomicInteger();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int nextCount() {
|
|
||||||
return atomicCounter.getAndIncrement();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package services;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This interface demonstrates how to create a component that is injected
|
|
||||||
* into a controller. The interface represents a counter that returns a
|
|
||||||
* incremented number each time it is called.
|
|
||||||
*
|
|
||||||
* The {@link Modules} class binds this interface to the
|
|
||||||
* {@link AtomicCounter} implementation.
|
|
||||||
*/
|
|
||||||
public interface Counter {
|
|
||||||
int nextCount();
|
|
||||||
}
|
|
|
@ -1,20 +1,5 @@
|
||||||
@*
|
@()
|
||||||
* This template takes a single argument, a String containing a
|
|
||||||
* message to display.
|
|
||||||
*@
|
|
||||||
@(message: String)
|
|
||||||
|
|
||||||
@*
|
|
||||||
* Call the `main` template with two arguments. The first
|
|
||||||
* argument is a `String` with the title of the page, the second
|
|
||||||
* argument is an `Html` object containing the body of the page.
|
|
||||||
*@
|
|
||||||
@main("Welcome to Play") {
|
@main("Welcome to Play") {
|
||||||
|
<h1>Welcome to Play!</h1>
|
||||||
@*
|
|
||||||
* Get an `Html` object by calling the built-in Play welcome
|
|
||||||
* template and passing a `String` message.
|
|
||||||
*@
|
|
||||||
@play20.welcome(message, style = "Java")
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,12 @@
|
||||||
<title>@title</title>
|
<title>@title</title>
|
||||||
<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
|
<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
|
||||||
<link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
|
<link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
|
||||||
<script src="@routes.Assets.versioned("javascripts/hello.js")" type="text/javascript"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@* And here's where we render the `Html` object containing
|
@* And here's where we render the `Html` object containing
|
||||||
* the page content. *@
|
* the page content. *@
|
||||||
@content
|
@content
|
||||||
|
|
||||||
|
<script src="@routes.Assets.versioned("javascripts/main.js")" type="text/javascript"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,397 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
### ------------------------------- ###
|
|
||||||
### Helper methods for BASH scripts ###
|
|
||||||
### ------------------------------- ###
|
|
||||||
|
|
||||||
realpath () {
|
|
||||||
(
|
|
||||||
TARGET_FILE="$1"
|
|
||||||
FIX_CYGPATH="$2"
|
|
||||||
|
|
||||||
cd "$(dirname "$TARGET_FILE")"
|
|
||||||
TARGET_FILE=$(basename "$TARGET_FILE")
|
|
||||||
|
|
||||||
COUNT=0
|
|
||||||
while [ -L "$TARGET_FILE" -a $COUNT -lt 100 ]
|
|
||||||
do
|
|
||||||
TARGET_FILE=$(readlink "$TARGET_FILE")
|
|
||||||
cd "$(dirname "$TARGET_FILE")"
|
|
||||||
TARGET_FILE=$(basename "$TARGET_FILE")
|
|
||||||
COUNT=$(($COUNT + 1))
|
|
||||||
done
|
|
||||||
|
|
||||||
# make sure we grab the actual windows path, instead of cygwin's path.
|
|
||||||
if [[ "x$FIX_CYGPATH" != "x" ]]; then
|
|
||||||
echo "$(cygwinpath "$(pwd -P)/$TARGET_FILE")"
|
|
||||||
else
|
|
||||||
echo "$(pwd -P)/$TARGET_FILE"
|
|
||||||
fi
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Uses uname to detect if we're in the odd cygwin environment.
|
|
||||||
is_cygwin() {
|
|
||||||
local os=$(uname -s)
|
|
||||||
case "$os" in
|
|
||||||
CYGWIN*) return 0 ;;
|
|
||||||
*) return 1 ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO - Use nicer bash-isms here.
|
|
||||||
CYGWIN_FLAG=$(if is_cygwin; then echo true; else echo false; fi)
|
|
||||||
|
|
||||||
|
|
||||||
# This can fix cygwin style /cygdrive paths so we get the
|
|
||||||
# windows style paths.
|
|
||||||
cygwinpath() {
|
|
||||||
local file="$1"
|
|
||||||
if [[ "$CYGWIN_FLAG" == "true" ]]; then
|
|
||||||
echo $(cygpath -w $file)
|
|
||||||
else
|
|
||||||
echo $file
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Make something URI friendly
|
|
||||||
make_url() {
|
|
||||||
url="$1"
|
|
||||||
local nospaces=${url// /%20}
|
|
||||||
if is_cygwin; then
|
|
||||||
echo "/${nospaces//\\//}"
|
|
||||||
else
|
|
||||||
echo "$nospaces"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
declare -a residual_args
|
|
||||||
declare -a java_args
|
|
||||||
declare -a scalac_args
|
|
||||||
declare -a sbt_commands
|
|
||||||
declare java_cmd=java
|
|
||||||
declare java_version
|
|
||||||
declare -r real_script_path="$(realpath "$0")"
|
|
||||||
declare -r sbt_home="$(realpath "$(dirname "$(dirname "$real_script_path")")")"
|
|
||||||
declare -r sbt_bin_dir="$(dirname "$real_script_path")"
|
|
||||||
declare -r app_version="1.3.10"
|
|
||||||
|
|
||||||
declare -r script_name=activator
|
|
||||||
declare -r java_opts=( "${ACTIVATOR_OPTS[@]}" "${SBT_OPTS[@]}" "${JAVA_OPTS[@]}" "${java_opts[@]}" )
|
|
||||||
userhome="$HOME"
|
|
||||||
if is_cygwin; then
|
|
||||||
# cygwin sets home to something f-d up, set to real windows homedir
|
|
||||||
userhome="$USERPROFILE"
|
|
||||||
fi
|
|
||||||
declare -r activator_user_home_dir="${userhome}/.activator"
|
|
||||||
declare -r java_opts_config_home="${activator_user_home_dir}/activatorconfig.txt"
|
|
||||||
declare -r java_opts_config_version="${activator_user_home_dir}/${app_version}/activatorconfig.txt"
|
|
||||||
|
|
||||||
echoerr () {
|
|
||||||
echo 1>&2 "$@"
|
|
||||||
}
|
|
||||||
vlog () {
|
|
||||||
[[ $verbose || $debug ]] && echoerr "$@"
|
|
||||||
}
|
|
||||||
dlog () {
|
|
||||||
[[ $debug ]] && echoerr "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
jar_file () {
|
|
||||||
echo "$(cygwinpath "${sbt_home}/libexec/activator-launch-${app_version}.jar")"
|
|
||||||
}
|
|
||||||
|
|
||||||
acquire_sbt_jar () {
|
|
||||||
sbt_jar="$(jar_file)"
|
|
||||||
|
|
||||||
if [[ ! -f "$sbt_jar" ]]; then
|
|
||||||
echoerr "Could not find launcher jar: $sbt_jar"
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
execRunner () {
|
|
||||||
# print the arguments one to a line, quoting any containing spaces
|
|
||||||
[[ $verbose || $debug ]] && echo "# Executing command line:" && {
|
|
||||||
for arg; do
|
|
||||||
if printf "%s\n" "$arg" | grep -q ' '; then
|
|
||||||
printf "\"%s\"\n" "$arg"
|
|
||||||
else
|
|
||||||
printf "%s\n" "$arg"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# THis used to be exec, but we loose the ability to re-hook stty then
|
|
||||||
# for cygwin... Maybe we should flag the feature here...
|
|
||||||
"$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
addJava () {
|
|
||||||
dlog "[addJava] arg = '$1'"
|
|
||||||
java_args=( "${java_args[@]}" "$1" )
|
|
||||||
}
|
|
||||||
addSbt () {
|
|
||||||
dlog "[addSbt] arg = '$1'"
|
|
||||||
sbt_commands=( "${sbt_commands[@]}" "$1" )
|
|
||||||
}
|
|
||||||
addResidual () {
|
|
||||||
dlog "[residual] arg = '$1'"
|
|
||||||
residual_args=( "${residual_args[@]}" "$1" )
|
|
||||||
}
|
|
||||||
addDebugger () {
|
|
||||||
addJava "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
get_mem_opts () {
|
|
||||||
# if we detect any of these settings in ${JAVA_OPTS} we need to NOT output our settings.
|
|
||||||
# The reason is the Xms/Xmx, if they don't line up, cause errors.
|
|
||||||
if [[ "${JAVA_OPTS}" == *-Xmx* ]] || [[ "${JAVA_OPTS}" == *-Xms* ]] || [[ "${JAVA_OPTS}" == *-XX:MaxPermSize* ]] || [[ "${JAVA_OPTS}" == *-XX:MaxMetaspaceSize* ]] || [[ "${JAVA_OPTS}" == *-XX:ReservedCodeCacheSize* ]]; then
|
|
||||||
echo ""
|
|
||||||
else
|
|
||||||
# a ham-fisted attempt to move some memory settings in concert
|
|
||||||
# so they need not be messed around with individually.
|
|
||||||
local mem=${1:-1024}
|
|
||||||
local codecache=$(( $mem / 8 ))
|
|
||||||
(( $codecache > 128 )) || codecache=128
|
|
||||||
(( $codecache < 512 )) || codecache=512
|
|
||||||
local class_metadata_size=$(( $codecache * 2 ))
|
|
||||||
local class_metadata_opt=$([[ "$java_version" < "1.8" ]] && echo "MaxPermSize" || echo "MaxMetaspaceSize")
|
|
||||||
|
|
||||||
echo "-Xms${mem}m -Xmx${mem}m -XX:ReservedCodeCacheSize=${codecache}m -XX:${class_metadata_opt}=${class_metadata_size}m"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
require_arg () {
|
|
||||||
local type="$1"
|
|
||||||
local opt="$2"
|
|
||||||
local arg="$3"
|
|
||||||
if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then
|
|
||||||
echo "$opt requires <$type> argument"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
is_function_defined() {
|
|
||||||
declare -f "$1" > /dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
# If we're *not* running in a terminal, and we don't have any arguments, then we need to add the 'ui' parameter
|
|
||||||
detect_terminal_for_ui() {
|
|
||||||
[[ ! -t 0 ]] && [[ "${#residual_args}" == "0" ]] && {
|
|
||||||
addResidual "ui"
|
|
||||||
}
|
|
||||||
# SPECIAL TEST FOR MAC
|
|
||||||
[[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]] && [[ "${#residual_args}" == "0" ]] && {
|
|
||||||
echo "Detected MAC OSX launched script...."
|
|
||||||
echo "Swapping to UI"
|
|
||||||
addResidual "ui"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
process_args () {
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
-h|-help) usage; exit 1 ;;
|
|
||||||
-v|-verbose) verbose=1 && shift ;;
|
|
||||||
-d|-debug) debug=1 && shift ;;
|
|
||||||
|
|
||||||
-ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;;
|
|
||||||
-mem) require_arg integer "$1" "$2" && sbt_mem="$2" && shift 2 ;;
|
|
||||||
-jvm-debug) require_arg port "$1" "$2" && addDebugger $2 && shift 2 ;;
|
|
||||||
-batch) exec </dev/null && shift ;;
|
|
||||||
|
|
||||||
-sbt-jar) require_arg path "$1" "$2" && sbt_jar="$2" && shift 2 ;;
|
|
||||||
-sbt-version) require_arg version "$1" "$2" && sbt_version="$2" && shift 2 ;;
|
|
||||||
-java-home) require_arg path "$1" "$2" && java_cmd="$2/bin/java" && shift 2 ;;
|
|
||||||
|
|
||||||
-D*) addJava "$1" && shift ;;
|
|
||||||
-J*) addJava "${1:2}" && shift ;;
|
|
||||||
*) addResidual "$1" && shift ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
is_function_defined process_my_args && {
|
|
||||||
myargs=("${residual_args[@]}")
|
|
||||||
residual_args=()
|
|
||||||
process_my_args "${myargs[@]}"
|
|
||||||
}
|
|
||||||
|
|
||||||
java_version=$("$java_cmd" -Xmx512M -version 2>&1 | awk -F '"' '/version/ {print $2}')
|
|
||||||
vlog "[process_args] java_version = '$java_version'"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Detect that we have java installed.
|
|
||||||
checkJava() {
|
|
||||||
local required_version="$1"
|
|
||||||
# Now check to see if it's a good enough version
|
|
||||||
if [[ "$java_version" == "" ]]; then
|
|
||||||
echo
|
|
||||||
echo No java installations was detected.
|
|
||||||
echo Please go to http://www.java.com/getjava/ and download
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
elif [[ ! "$java_version" > "$required_version" ]]; then
|
|
||||||
echo
|
|
||||||
echo The java installation you have is not up to date
|
|
||||||
echo $script_name requires at least version $required_version+, you have
|
|
||||||
echo version $java_version
|
|
||||||
echo
|
|
||||||
echo Please go to http://www.java.com/getjava/ and download
|
|
||||||
echo a valid Java Runtime and install before running $script_name.
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
run() {
|
|
||||||
# no jar? download it.
|
|
||||||
[[ -f "$sbt_jar" ]] || acquire_sbt_jar "$sbt_version" || {
|
|
||||||
# still no jar? uh-oh.
|
|
||||||
echo "Download failed. Obtain the sbt-launch.jar manually and place it at $sbt_jar"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# process the combined args, then reset "$@" to the residuals
|
|
||||||
process_args "$@"
|
|
||||||
detect_terminal_for_ui
|
|
||||||
set -- "${residual_args[@]}"
|
|
||||||
argumentCount=$#
|
|
||||||
|
|
||||||
# TODO - java check should be configurable...
|
|
||||||
checkJava "1.6"
|
|
||||||
|
|
||||||
#If we're in cygwin, we should use the windows config, and terminal hacks
|
|
||||||
if [[ "$CYGWIN_FLAG" == "true" ]]; then
|
|
||||||
stty -icanon min 1 -echo > /dev/null 2>&1
|
|
||||||
addJava "-Djline.terminal=jline.UnixTerminal"
|
|
||||||
addJava "-Dsbt.cygwin=true"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# run sbt
|
|
||||||
execRunner "$java_cmd" \
|
|
||||||
"-Dactivator.home=$(make_url "$sbt_home")" \
|
|
||||||
${SBT_OPTS:-$default_sbt_opts} \
|
|
||||||
$(get_mem_opts $sbt_mem) \
|
|
||||||
${JAVA_OPTS} \
|
|
||||||
${java_args[@]} \
|
|
||||||
-jar "$sbt_jar" \
|
|
||||||
"${sbt_commands[@]}" \
|
|
||||||
"${residual_args[@]}"
|
|
||||||
|
|
||||||
exit_code=$?
|
|
||||||
|
|
||||||
# Clean up the terminal from cygwin hacks.
|
|
||||||
if [[ "$CYGWIN_FLAG" == "true" ]]; then
|
|
||||||
stty icanon echo > /dev/null 2>&1
|
|
||||||
fi
|
|
||||||
exit $exit_code
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy"
|
|
||||||
declare -r sbt_opts_file=".sbtopts"
|
|
||||||
declare -r etc_sbt_opts_file="${sbt_home}/conf/sbtopts"
|
|
||||||
declare -r win_sbt_opts_file="${sbt_home}/conf/sbtconfig.txt"
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<EOM
|
|
||||||
Usage: $script_name [options]
|
|
||||||
|
|
||||||
Command:
|
|
||||||
ui Start the Activator UI
|
|
||||||
new [name] [template-id] Create a new project with [name] using template [template-id]
|
|
||||||
list-templates Print all available template names
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h | -help print this message
|
|
||||||
-v | -verbose this runner is chattier
|
|
||||||
-d | -debug set sbt log level to debug
|
|
||||||
-no-colors disable ANSI color codes
|
|
||||||
-sbt-create start sbt even if current directory contains no sbt project
|
|
||||||
-sbt-dir <path> path to global settings/plugins directory (default: ~/.sbt)
|
|
||||||
-sbt-boot <path> path to shared boot directory (default: ~/.sbt/boot in 0.11 series)
|
|
||||||
-ivy <path> path to local Ivy repository (default: ~/.ivy2)
|
|
||||||
-mem <integer> set memory options (default: $sbt_mem, which is $(get_mem_opts $sbt_mem))
|
|
||||||
-no-share use all local caches; no sharing
|
|
||||||
-no-global uses global caches, but does not use global ~/.sbt directory.
|
|
||||||
-jvm-debug <port> Turn on JVM debugging, open at the given port.
|
|
||||||
-batch Disable interactive mode
|
|
||||||
|
|
||||||
# sbt version (default: from project/build.properties if present, else latest release)
|
|
||||||
-sbt-version <version> use the specified version of sbt
|
|
||||||
-sbt-jar <path> use the specified jar as the sbt launcher
|
|
||||||
-sbt-rc use an RC version of sbt
|
|
||||||
-sbt-snapshot use a snapshot version of sbt
|
|
||||||
|
|
||||||
# java version (default: java from PATH, currently $(java -version 2>&1 | grep version))
|
|
||||||
-java-home <path> alternate JAVA_HOME
|
|
||||||
|
|
||||||
# jvm options and output control
|
|
||||||
JAVA_OPTS environment variable, if unset uses "$java_opts"
|
|
||||||
SBT_OPTS environment variable, if unset uses "$default_sbt_opts"
|
|
||||||
ACTIVATOR_OPTS Environment variable, if unset uses ""
|
|
||||||
.sbtopts if this file exists in the current directory, it is
|
|
||||||
prepended to the runner args
|
|
||||||
/etc/sbt/sbtopts if this file exists, it is prepended to the runner args
|
|
||||||
-Dkey=val pass -Dkey=val directly to the java runtime
|
|
||||||
-J-X pass option -X directly to the java runtime
|
|
||||||
(-J is stripped)
|
|
||||||
-S-X add -X to sbt's scalacOptions (-S is stripped)
|
|
||||||
|
|
||||||
In the case of duplicated or conflicting options, the order above
|
|
||||||
shows precedence: JAVA_OPTS lowest, command line options highest.
|
|
||||||
EOM
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
process_my_args () {
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
-no-colors) addJava "-Dsbt.log.noformat=true" && shift ;;
|
|
||||||
-no-share) addJava "$noshare_opts" && shift ;;
|
|
||||||
-no-global) addJava "-Dsbt.global.base=$(pwd)/project/.sbtboot" && shift ;;
|
|
||||||
-sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;;
|
|
||||||
-sbt-dir) require_arg path "$1" "$2" && addJava "-Dsbt.global.base=$2" && shift 2 ;;
|
|
||||||
-debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;;
|
|
||||||
-batch) exec </dev/null && shift ;;
|
|
||||||
|
|
||||||
-sbt-create) sbt_create=true && shift ;;
|
|
||||||
|
|
||||||
*) addResidual "$1" && shift ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Now, ensure sbt version is used.
|
|
||||||
[[ "${sbt_version}XXX" != "XXX" ]] && addJava "-Dsbt.version=$sbt_version"
|
|
||||||
}
|
|
||||||
|
|
||||||
loadConfigFile() {
|
|
||||||
cat "$1" | sed '/^\#/d' | while read line; do
|
|
||||||
eval echo $line
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO - Pull in config based on operating system... (MSYS + cygwin should pull in txt file).
|
|
||||||
# Here we pull in the global settings configuration.
|
|
||||||
[[ -f "$etc_sbt_opts_file" ]] && set -- $(loadConfigFile "$etc_sbt_opts_file") "$@"
|
|
||||||
# -- Windows behavior stub'd
|
|
||||||
# JAVA_OPTS=$(cat "$WDIR/sbtconfig.txt" | sed -e 's/\r//g' -e 's/^#.*$//g' | sed ':a;N;$!ba;s/\n/ /g')
|
|
||||||
|
|
||||||
|
|
||||||
# Pull in the project-level config file, if it exists.
|
|
||||||
[[ -f "$sbt_opts_file" ]] && set -- $(loadConfigFile "$sbt_opts_file") "$@"
|
|
||||||
|
|
||||||
# if configuration files exist, prepend their contents to the java args so it can be processed by this runner
|
|
||||||
# a "versioned" config trumps one on the top level
|
|
||||||
if [[ -f "$java_opts_config_version" ]]; then
|
|
||||||
addConfigOpts $(loadConfigFile "$java_opts_config_version")
|
|
||||||
elif [[ -f "$java_opts_config_home" ]]; then
|
|
||||||
addConfigOpts $(loadConfigFile "$java_opts_config_home")
|
|
||||||
fi
|
|
||||||
|
|
||||||
run "$@"
|
|
|
@ -1,248 +0,0 @@
|
||||||
@REM activator launcher script
|
|
||||||
@REM
|
|
||||||
@REM Environment:
|
|
||||||
@REM In order for Activator to work you must have Java available on the classpath
|
|
||||||
@REM JAVA_HOME - location of a JDK home dir (optional if java on path)
|
|
||||||
@REM CFG_OPTS - JVM options (optional)
|
|
||||||
@REM Configuration:
|
|
||||||
@REM activatorconfig.txt found in the ACTIVATOR_HOME or ACTIVATOR_HOME/ACTIVATOR_VERSION
|
|
||||||
@setlocal enabledelayedexpansion
|
|
||||||
|
|
||||||
@echo off
|
|
||||||
|
|
||||||
set "var1=%~1"
|
|
||||||
if defined var1 (
|
|
||||||
if "%var1%"=="help" (
|
|
||||||
echo.
|
|
||||||
echo Usage activator [options] [command]
|
|
||||||
echo.
|
|
||||||
echo Commands:
|
|
||||||
echo ui Start the Activator UI
|
|
||||||
echo new [name] [template-id] Create a new project with [name] using template [template-id]
|
|
||||||
echo list-templates Print all available template names
|
|
||||||
echo help Print this message
|
|
||||||
echo.
|
|
||||||
echo Options:
|
|
||||||
echo -jvm-debug [port] Turn on JVM debugging, open at the given port. Defaults to 9999 if no port given.
|
|
||||||
echo.
|
|
||||||
echo Environment variables ^(read from context^):
|
|
||||||
echo JAVA_OPTS Environment variable, if unset uses ""
|
|
||||||
echo SBT_OPTS Environment variable, if unset uses ""
|
|
||||||
echo ACTIVATOR_OPTS Environment variable, if unset uses ""
|
|
||||||
echo.
|
|
||||||
echo Please note that in order for Activator to work you must have Java available on the classpath
|
|
||||||
echo.
|
|
||||||
goto :end
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
@REM determine ACTIVATOR_HOME environment variable
|
|
||||||
set BIN_DIRECTORY=%~dp0
|
|
||||||
set BIN_DIRECTORY=%BIN_DIRECTORY:~0,-1%
|
|
||||||
for %%d in (%BIN_DIRECTORY%) do set ACTIVATOR_HOME=%%~dpd
|
|
||||||
set ACTIVATOR_HOME=%ACTIVATOR_HOME:~0,-1%
|
|
||||||
|
|
||||||
echo ACTIVATOR_HOME=%ACTIVATOR_HOME%
|
|
||||||
|
|
||||||
set ERROR_CODE=0
|
|
||||||
set APP_VERSION=1.3.10
|
|
||||||
set ACTIVATOR_LAUNCH_JAR=activator-launch-%APP_VERSION%.jar
|
|
||||||
|
|
||||||
rem Detect if we were double clicked, although theoretically A user could
|
|
||||||
rem manually run cmd /c
|
|
||||||
for %%x in (%cmdcmdline%) do if %%~x==/c set DOUBLECLICKED=1
|
|
||||||
|
|
||||||
set SBT_HOME=%BIN_DIRECTORY
|
|
||||||
|
|
||||||
rem Detect if we were double clicked, although theoretically A user could
|
|
||||||
rem manually run cmd /c
|
|
||||||
for %%x in (%cmdcmdline%) do if %%~x==/c set DOUBLECLICKED=1
|
|
||||||
|
|
||||||
rem FIRST we load the config file of extra options.
|
|
||||||
set FN=%SBT_HOME%\..\conf\sbtconfig.txt
|
|
||||||
set CFG_OPTS=
|
|
||||||
FOR /F "tokens=* eol=# usebackq delims=" %%i IN ("%FN%") DO (
|
|
||||||
set DO_NOT_REUSE_ME=%%i
|
|
||||||
rem ZOMG (Part #2) WE use !! here to delay the expansion of
|
|
||||||
rem CFG_OPTS, otherwise it remains "" for this loop.
|
|
||||||
set CFG_OPTS=!CFG_OPTS! !DO_NOT_REUSE_ME!
|
|
||||||
)
|
|
||||||
|
|
||||||
rem FIRST we load a config file of extra options (if there is one)
|
|
||||||
set "CFG_FILE_HOME=%UserProfile%\.activator\activatorconfig.txt"
|
|
||||||
set "CFG_FILE_VERSION=%UserProfile%\.activator\%APP_VERSION%\activatorconfig.txt"
|
|
||||||
if exist %CFG_FILE_VERSION% (
|
|
||||||
FOR /F "tokens=* eol=# usebackq delims=" %%i IN ("%CFG_FILE_VERSION%") DO (
|
|
||||||
set DO_NOT_REUSE_ME=%%i
|
|
||||||
rem ZOMG (Part #2) WE use !! here to delay the expansion of
|
|
||||||
rem CFG_OPTS, otherwise it remains "" for this loop.
|
|
||||||
set CFG_OPTS=!CFG_OPTS! !DO_NOT_REUSE_ME!
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if "%CFG_OPTS%"=="" (
|
|
||||||
if exist %CFG_FILE_HOME% (
|
|
||||||
FOR /F "tokens=* eol=# usebackq delims=" %%i IN ("%CFG_FILE_HOME%") DO (
|
|
||||||
set DO_NOT_REUSE_ME=%%i
|
|
||||||
rem ZOMG (Part #2) WE use !! here to delay the expansion of
|
|
||||||
rem CFG_OPTS, otherwise it remains "" for this loop.
|
|
||||||
set CFG_OPTS=!CFG_OPTS! !DO_NOT_REUSE_ME!
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
rem We use the value of the JAVACMD environment variable if defined
|
|
||||||
set _JAVACMD=%JAVACMD%
|
|
||||||
|
|
||||||
if "%_JAVACMD%"=="" (
|
|
||||||
if not "%JAVA_HOME%"=="" (
|
|
||||||
if exist "%JAVA_HOME%\bin\java.exe" set "_JAVACMD=%JAVA_HOME%\bin\java.exe"
|
|
||||||
|
|
||||||
rem if there is a java home set we make sure it is the first picked up when invoking 'java'
|
|
||||||
SET "PATH=%JAVA_HOME%\bin;%PATH%"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%_JAVACMD%"=="" set _JAVACMD=java
|
|
||||||
|
|
||||||
rem Detect if this java is ok to use.
|
|
||||||
for /F %%j in ('"%_JAVACMD%" -version 2^>^&1') do (
|
|
||||||
if %%~j==java set JAVAINSTALLED=1
|
|
||||||
if %%~j==openjdk set JAVAINSTALLED=1
|
|
||||||
)
|
|
||||||
|
|
||||||
rem Detect the same thing about javac
|
|
||||||
if "%_JAVACCMD%"=="" (
|
|
||||||
if not "%JAVA_HOME%"=="" (
|
|
||||||
if exist "%JAVA_HOME%\bin\javac.exe" set "_JAVACCMD=%JAVA_HOME%\bin\javac.exe"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if "%_JAVACCMD%"=="" set _JAVACCMD=javac
|
|
||||||
for /F %%j in ('"%_JAVACCMD%" -version 2^>^&1') do (
|
|
||||||
if %%~j==javac set JAVACINSTALLED=1
|
|
||||||
)
|
|
||||||
|
|
||||||
rem BAT has no logical or, so we do it OLD SCHOOL! Oppan Redmond Style
|
|
||||||
set JAVAOK=true
|
|
||||||
if not defined JAVAINSTALLED set JAVAOK=false
|
|
||||||
if not defined JAVACINSTALLED set JAVAOK=false
|
|
||||||
|
|
||||||
if "%JAVAOK%"=="false" (
|
|
||||||
echo.
|
|
||||||
echo A Java JDK is not installed or can't be found.
|
|
||||||
if not "%JAVA_HOME%"=="" (
|
|
||||||
echo JAVA_HOME = "%JAVA_HOME%"
|
|
||||||
)
|
|
||||||
echo.
|
|
||||||
echo Please go to
|
|
||||||
echo http://www.oracle.com/technetwork/java/javase/downloads/index.html
|
|
||||||
echo and download a valid Java JDK and install before running Activator.
|
|
||||||
echo.
|
|
||||||
echo If you think this message is in error, please check
|
|
||||||
echo your environment variables to see if "java.exe" and "javac.exe" are
|
|
||||||
echo available via JAVA_HOME or PATH.
|
|
||||||
echo.
|
|
||||||
if defined DOUBLECLICKED pause
|
|
||||||
exit /B 1
|
|
||||||
)
|
|
||||||
|
|
||||||
rem Check what Java version is being used to determine what memory options to use
|
|
||||||
for /f "tokens=3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do (
|
|
||||||
set JAVA_VERSION=%%g
|
|
||||||
)
|
|
||||||
|
|
||||||
rem Strips away the " characters
|
|
||||||
set JAVA_VERSION=%JAVA_VERSION:"=%
|
|
||||||
|
|
||||||
rem TODO Check if there are existing mem settings in JAVA_OPTS/CFG_OPTS and use those instead of the below
|
|
||||||
for /f "delims=. tokens=1-3" %%v in ("%JAVA_VERSION%") do (
|
|
||||||
set MAJOR=%%v
|
|
||||||
set MINOR=%%w
|
|
||||||
set BUILD=%%x
|
|
||||||
|
|
||||||
set META_SIZE=-XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=256M
|
|
||||||
if "!MINOR!" LSS "8" (
|
|
||||||
set META_SIZE=-XX:PermSize=64M -XX:MaxPermSize=256M
|
|
||||||
)
|
|
||||||
|
|
||||||
set MEM_OPTS=!META_SIZE!
|
|
||||||
)
|
|
||||||
|
|
||||||
rem We use the value of the JAVA_OPTS environment variable if defined, rather than the config.
|
|
||||||
set _JAVA_OPTS=%JAVA_OPTS%
|
|
||||||
if "%_JAVA_OPTS%"=="" set _JAVA_OPTS=%CFG_OPTS%
|
|
||||||
|
|
||||||
set DEBUG_OPTS=
|
|
||||||
|
|
||||||
rem Loop through the arguments, building remaining args in args variable
|
|
||||||
set args=
|
|
||||||
:argsloop
|
|
||||||
if not "%~1"=="" (
|
|
||||||
rem Checks if the argument contains "-D" and if true, adds argument 1 with 2 and puts an equal sign between them.
|
|
||||||
rem This is done since batch considers "=" to be a delimiter so we need to circumvent this behavior with a small hack.
|
|
||||||
set arg1=%~1
|
|
||||||
if "!arg1:~0,2!"=="-D" (
|
|
||||||
set "args=%args% "%~1"="%~2""
|
|
||||||
shift
|
|
||||||
shift
|
|
||||||
goto argsloop
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%~1"=="-jvm-debug" (
|
|
||||||
if not "%~2"=="" (
|
|
||||||
rem This piece of magic somehow checks that an argument is a number
|
|
||||||
for /F "delims=0123456789" %%i in ("%~2") do (
|
|
||||||
set var="%%i"
|
|
||||||
)
|
|
||||||
if defined var (
|
|
||||||
rem Not a number, assume no argument given and default to 9999
|
|
||||||
set JPDA_PORT=9999
|
|
||||||
) else (
|
|
||||||
rem Port was given, shift arguments
|
|
||||||
set JPDA_PORT=%~2
|
|
||||||
shift
|
|
||||||
)
|
|
||||||
) else (
|
|
||||||
set JPDA_PORT=9999
|
|
||||||
)
|
|
||||||
shift
|
|
||||||
|
|
||||||
set DEBUG_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=!JPDA_PORT!
|
|
||||||
goto argsloop
|
|
||||||
)
|
|
||||||
rem else
|
|
||||||
set "args=%args% "%~1""
|
|
||||||
shift
|
|
||||||
goto argsloop
|
|
||||||
)
|
|
||||||
|
|
||||||
:run
|
|
||||||
|
|
||||||
if "!args!"=="" (
|
|
||||||
if defined DOUBLECLICKED (
|
|
||||||
set CMDS="ui"
|
|
||||||
) else set CMDS=!args!
|
|
||||||
) else set CMDS=!args!
|
|
||||||
|
|
||||||
rem We add a / in front, so we get file:///C: instead of file://C:
|
|
||||||
rem Java considers the later a UNC path.
|
|
||||||
rem We also attempt a solid effort at making it URI friendly.
|
|
||||||
rem We don't even bother with UNC paths.
|
|
||||||
set JAVA_FRIENDLY_HOME_1=/!ACTIVATOR_HOME:\=/!
|
|
||||||
set JAVA_FRIENDLY_HOME=/!JAVA_FRIENDLY_HOME_1: =%%20!
|
|
||||||
|
|
||||||
rem Checks if the command contains spaces to know if it should be wrapped in quotes or not
|
|
||||||
set NON_SPACED_CMD=%_JAVACMD: =%
|
|
||||||
if "%_JAVACMD%"=="%NON_SPACED_CMD%" %_JAVACMD% %DEBUG_OPTS% %MEM_OPTS% %ACTIVATOR_OPTS% %SBT_OPTS% %_JAVA_OPTS% "-Dactivator.home=%JAVA_FRIENDLY_HOME%" -jar "%ACTIVATOR_HOME%\libexec\%ACTIVATOR_LAUNCH_JAR%" %CMDS%
|
|
||||||
if NOT "%_JAVACMD%"=="%NON_SPACED_CMD%" "%_JAVACMD%" %DEBUG_OPTS% %MEM_OPTS% %ACTIVATOR_OPTS% %SBT_OPTS% %_JAVA_OPTS% "-Dactivator.home=%JAVA_FRIENDLY_HOME%" -jar "%ACTIVATOR_HOME%\libexec\%ACTIVATOR_LAUNCH_JAR%" %CMDS%
|
|
||||||
|
|
||||||
if ERRORLEVEL 1 goto error
|
|
||||||
goto end
|
|
||||||
|
|
||||||
:error
|
|
||||||
set ERROR_CODE=1
|
|
||||||
|
|
||||||
:end
|
|
||||||
|
|
||||||
@endlocal
|
|
||||||
|
|
||||||
exit /B %ERROR_CODE%
|
|
|
@ -1,13 +1,10 @@
|
||||||
name := """student-api"""
|
name := """introduction"""
|
||||||
|
organization := "com.baeldung"
|
||||||
|
|
||||||
version := "1.0-SNAPSHOT"
|
version := "1.0-SNAPSHOT"
|
||||||
|
|
||||||
lazy val root = (project in file(".")).enablePlugins(PlayJava)
|
lazy val root = (project in file(".")).enablePlugins(PlayJava)
|
||||||
|
|
||||||
scalaVersion := "2.11.7"
|
scalaVersion := "2.13.0"
|
||||||
|
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies += guice
|
||||||
javaJdbc,
|
|
||||||
cache,
|
|
||||||
javaWs
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,353 +1,2 @@
|
||||||
# This is the main configuration file for the application.
|
# This is the main configuration file for the application.
|
||||||
# https://www.playframework.com/documentation/latest/ConfigFile
|
# https://www.playframework.com/documentation/latest/ConfigFile
|
||||||
# ~~~~~
|
|
||||||
# Play uses HOCON as its configuration file format. HOCON has a number
|
|
||||||
# of advantages over other config formats, but there are two things that
|
|
||||||
# can be used when modifying settings.
|
|
||||||
#
|
|
||||||
# You can include other configuration files in this main application.conf file:
|
|
||||||
#include "extra-config.conf"
|
|
||||||
#
|
|
||||||
# You can declare variables and substitute for them:
|
|
||||||
#mykey = ${some.value}
|
|
||||||
#
|
|
||||||
# And if an environment variable exists when there is no other subsitution, then
|
|
||||||
# HOCON will fall back to substituting environment variable:
|
|
||||||
#mykey = ${JAVA_HOME}
|
|
||||||
|
|
||||||
## Akka
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaAkka#Configuration
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaAkka#Configuration
|
|
||||||
# ~~~~~
|
|
||||||
# Play uses Akka internally and exposes Akka Streams and actors in Websockets and
|
|
||||||
# other streaming HTTP responses.
|
|
||||||
akka {
|
|
||||||
# "akka.log-config-on-start" is extraordinarly useful because it log the complete
|
|
||||||
# configuration at INFO level, including defaults and overrides, so it s worth
|
|
||||||
# putting at the very top.
|
|
||||||
#
|
|
||||||
# Put the following in your conf/logback.xml file:
|
|
||||||
#
|
|
||||||
# <logger name="akka.actor" level="INFO" />
|
|
||||||
#
|
|
||||||
# And then uncomment this line to debug the configuration.
|
|
||||||
#
|
|
||||||
#log-config-on-start = true
|
|
||||||
}
|
|
||||||
|
|
||||||
## Secret key
|
|
||||||
# http://www.playframework.com/documentation/latest/ApplicationSecret
|
|
||||||
# ~~~~~
|
|
||||||
# The secret key is used to sign Play's session cookie.
|
|
||||||
# This must be changed for production, but we don't recommend you change it in this file.
|
|
||||||
play.crypto.secret = "changeme"
|
|
||||||
|
|
||||||
## Modules
|
|
||||||
# https://www.playframework.com/documentation/latest/Modules
|
|
||||||
# ~~~~~
|
|
||||||
# Control which modules are loaded when Play starts. Note that modules are
|
|
||||||
# the replacement for "GlobalSettings", which are deprecated in 2.5.x.
|
|
||||||
# Please see https://www.playframework.com/documentation/latest/GlobalSettings
|
|
||||||
# for more information.
|
|
||||||
#
|
|
||||||
# You can also extend Play functionality by using one of the publically available
|
|
||||||
# Play modules: https://playframework.com/documentation/latest/ModuleDirectory
|
|
||||||
play.modules {
|
|
||||||
# By default, Play will load any class called Module that is defined
|
|
||||||
# in the root package (the "app" directory), or you can define them
|
|
||||||
# explicitly below.
|
|
||||||
# If there are any built-in modules that you want to disable, you can list them here.
|
|
||||||
#enabled += my.application.Module
|
|
||||||
|
|
||||||
# If there are any built-in modules that you want to disable, you can list them here.
|
|
||||||
#disabled += ""
|
|
||||||
}
|
|
||||||
|
|
||||||
## IDE
|
|
||||||
# https://www.playframework.com/documentation/latest/IDE
|
|
||||||
# ~~~~~
|
|
||||||
# Depending on your IDE, you can add a hyperlink for errors that will jump you
|
|
||||||
# directly to the code location in the IDE in dev mode. The following line makes
|
|
||||||
# use of the IntelliJ IDEA REST interface:
|
|
||||||
#play.editor="http://localhost:63342/api/file/?file=%s&line=%s"
|
|
||||||
|
|
||||||
## Internationalisation
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaI18N
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaI18N
|
|
||||||
# ~~~~~
|
|
||||||
# Play comes with its own i18n settings, which allow the user's preferred language
|
|
||||||
# to map through to internal messages, or allow the language to be stored in a cookie.
|
|
||||||
play.i18n {
|
|
||||||
# The application languages
|
|
||||||
langs = [ "en" ]
|
|
||||||
|
|
||||||
# Whether the language cookie should be secure or not
|
|
||||||
#langCookieSecure = true
|
|
||||||
|
|
||||||
# Whether the HTTP only attribute of the cookie should be set to true
|
|
||||||
#langCookieHttpOnly = true
|
|
||||||
}
|
|
||||||
|
|
||||||
## Play HTTP settings
|
|
||||||
# ~~~~~
|
|
||||||
play.http {
|
|
||||||
## Router
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaRouting
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaRouting
|
|
||||||
# ~~~~~
|
|
||||||
# Define the Router object to use for this application.
|
|
||||||
# This router will be looked up first when the application is starting up,
|
|
||||||
# so make sure this is the entry point.
|
|
||||||
# Furthermore, it's assumed your route file is named properly.
|
|
||||||
# So for an application router like `my.application.Router`,
|
|
||||||
# you may need to define a router file `conf/my.application.routes`.
|
|
||||||
# Default to Routes in the root package (aka "apps" folder) (and conf/routes)
|
|
||||||
#router = my.application.Router
|
|
||||||
|
|
||||||
## Action Creator
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaActionCreator
|
|
||||||
# ~~~~~
|
|
||||||
#actionCreator = null
|
|
||||||
|
|
||||||
## ErrorHandler
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaRouting
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaRouting
|
|
||||||
# ~~~~~
|
|
||||||
# If null, will attempt to load a class called ErrorHandler in the root package,
|
|
||||||
#errorHandler = null
|
|
||||||
|
|
||||||
## Filters
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaHttpFilters
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaHttpFilters
|
|
||||||
# ~~~~~
|
|
||||||
# Filters run code on every request. They can be used to perform
|
|
||||||
# common logic for all your actions, e.g. adding common headers.
|
|
||||||
# Defaults to "Filters" in the root package (aka "apps" folder)
|
|
||||||
# Alternatively you can explicitly register a class here.
|
|
||||||
#filters = my.application.Filters
|
|
||||||
|
|
||||||
## Session & Flash
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaSessionFlash
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaSessionFlash
|
|
||||||
# ~~~~~
|
|
||||||
session {
|
|
||||||
# Sets the cookie to be sent only over HTTPS.
|
|
||||||
#secure = true
|
|
||||||
|
|
||||||
# Sets the cookie to be accessed only by the server.
|
|
||||||
#httpOnly = true
|
|
||||||
|
|
||||||
# Sets the max-age field of the cookie to 5 minutes.
|
|
||||||
# NOTE: this only sets when the browser will discard the cookie. Play will consider any
|
|
||||||
# cookie value with a valid signature to be a valid session forever. To implement a server side session timeout,
|
|
||||||
# you need to put a timestamp in the session and check it at regular intervals to possibly expire it.
|
|
||||||
#maxAge = 300
|
|
||||||
|
|
||||||
# Sets the domain on the session cookie.
|
|
||||||
#domain = "example.com"
|
|
||||||
}
|
|
||||||
|
|
||||||
flash {
|
|
||||||
# Sets the cookie to be sent only over HTTPS.
|
|
||||||
#secure = true
|
|
||||||
|
|
||||||
# Sets the cookie to be accessed only by the server.
|
|
||||||
#httpOnly = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
## Netty Provider
|
|
||||||
# https://www.playframework.com/documentation/latest/SettingsNetty
|
|
||||||
# ~~~~~
|
|
||||||
play.server.netty {
|
|
||||||
# Whether the Netty wire should be logged
|
|
||||||
#log.wire = true
|
|
||||||
|
|
||||||
# If you run Play on Linux, you can use Netty's native socket transport
|
|
||||||
# for higher performance with less garbage.
|
|
||||||
#transport = "native"
|
|
||||||
}
|
|
||||||
|
|
||||||
## WS (HTTP Client)
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaWS#Configuring-WS
|
|
||||||
# ~~~~~
|
|
||||||
# The HTTP client primarily used for REST APIs. The default client can be
|
|
||||||
# configured directly, but you can also create different client instances
|
|
||||||
# with customized settings. You must enable this by adding to build.sbt:
|
|
||||||
#
|
|
||||||
# libraryDependencies += ws // or javaWs if using java
|
|
||||||
#
|
|
||||||
play.ws {
|
|
||||||
# Sets HTTP requests not to follow 302 requests
|
|
||||||
#followRedirects = false
|
|
||||||
|
|
||||||
# Sets the maximum number of open HTTP connections for the client.
|
|
||||||
#ahc.maxConnectionsTotal = 50
|
|
||||||
|
|
||||||
## WS SSL
|
|
||||||
# https://www.playframework.com/documentation/latest/WsSSL
|
|
||||||
# ~~~~~
|
|
||||||
ssl {
|
|
||||||
# Configuring HTTPS with Play WS does not require programming. You can
|
|
||||||
# set up both trustManager and keyManager for mutual authentication, and
|
|
||||||
# turn on JSSE debugging in development with a reload.
|
|
||||||
#debug.handshake = true
|
|
||||||
#trustManager = {
|
|
||||||
# stores = [
|
|
||||||
# { type = "JKS", path = "exampletrust.jks" }
|
|
||||||
# ]
|
|
||||||
#}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
## Cache
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaCache
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaCache
|
|
||||||
# ~~~~~
|
|
||||||
# Play comes with an integrated cache API that can reduce the operational
|
|
||||||
# overhead of repeated requests. You must enable this by adding to build.sbt:
|
|
||||||
#
|
|
||||||
# libraryDependencies += cache
|
|
||||||
#
|
|
||||||
play.cache {
|
|
||||||
# If you want to bind several caches, you can bind the individually
|
|
||||||
#bindCaches = ["db-cache", "user-cache", "session-cache"]
|
|
||||||
}
|
|
||||||
|
|
||||||
## Filters
|
|
||||||
# https://www.playframework.com/documentation/latest/Filters
|
|
||||||
# ~~~~~
|
|
||||||
# There are a number of built-in filters that can be enabled and configured
|
|
||||||
# to give Play greater security. You must enable this by adding to build.sbt:
|
|
||||||
#
|
|
||||||
# libraryDependencies += filters
|
|
||||||
#
|
|
||||||
play.filters {
|
|
||||||
## CORS filter configuration
|
|
||||||
# https://www.playframework.com/documentation/latest/CorsFilter
|
|
||||||
# ~~~~~
|
|
||||||
# CORS is a protocol that allows web applications to make requests from the browser
|
|
||||||
# across different domains.
|
|
||||||
# NOTE: You MUST apply the CORS configuration before the CSRF filter, as CSRF has
|
|
||||||
# dependencies on CORS settings.
|
|
||||||
cors {
|
|
||||||
# Filter paths by a whitelist of path prefixes
|
|
||||||
#pathPrefixes = ["/some/path", ...]
|
|
||||||
|
|
||||||
# The allowed origins. If null, all origins are allowed.
|
|
||||||
#allowedOrigins = ["http://www.example.com"]
|
|
||||||
|
|
||||||
# The allowed HTTP methods. If null, all methods are allowed
|
|
||||||
#allowedHttpMethods = ["GET", "POST"]
|
|
||||||
}
|
|
||||||
|
|
||||||
## CSRF Filter
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaCsrf#Applying-a-global-CSRF-filter
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaCsrf#Applying-a-global-CSRF-filter
|
|
||||||
# ~~~~~
|
|
||||||
# Play supports multiple methods for verifying that a request is not a CSRF request.
|
|
||||||
# The primary mechanism is a CSRF token. This token gets placed either in the query string
|
|
||||||
# or body of every form submitted, and also gets placed in the users session.
|
|
||||||
# Play then verifies that both tokens are present and match.
|
|
||||||
csrf {
|
|
||||||
# Sets the cookie to be sent only over HTTPS
|
|
||||||
#cookie.secure = true
|
|
||||||
|
|
||||||
# Defaults to CSRFErrorHandler in the root package.
|
|
||||||
#errorHandler = MyCSRFErrorHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
## Security headers filter configuration
|
|
||||||
# https://www.playframework.com/documentation/latest/SecurityHeaders
|
|
||||||
# ~~~~~
|
|
||||||
# Defines security headers that prevent XSS attacks.
|
|
||||||
# If enabled, then all options are set to the below configuration by default:
|
|
||||||
headers {
|
|
||||||
# The X-Frame-Options header. If null, the header is not set.
|
|
||||||
#frameOptions = "DENY"
|
|
||||||
|
|
||||||
# The X-XSS-Protection header. If null, the header is not set.
|
|
||||||
#xssProtection = "1; mode=block"
|
|
||||||
|
|
||||||
# The X-Content-Type-Options header. If null, the header is not set.
|
|
||||||
#contentTypeOptions = "nosniff"
|
|
||||||
|
|
||||||
# The X-Permitted-Cross-Domain-Policies header. If null, the header is not set.
|
|
||||||
#permittedCrossDomainPolicies = "master-only"
|
|
||||||
|
|
||||||
# The Content-Security-Policy header. If null, the header is not set.
|
|
||||||
#contentSecurityPolicy = "default-src 'self'"
|
|
||||||
}
|
|
||||||
|
|
||||||
## Allowed hosts filter configuration
|
|
||||||
# https://www.playframework.com/documentation/latest/AllowedHostsFilter
|
|
||||||
# ~~~~~
|
|
||||||
# Play provides a filter that lets you configure which hosts can access your application.
|
|
||||||
# This is useful to prevent cache poisoning attacks.
|
|
||||||
hosts {
|
|
||||||
# Allow requests to example.com, its subdomains, and localhost:9000.
|
|
||||||
#allowed = [".example.com", "localhost:9000"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
## Evolutions
|
|
||||||
# https://www.playframework.com/documentation/latest/Evolutions
|
|
||||||
# ~~~~~
|
|
||||||
# Evolutions allows database scripts to be automatically run on startup in dev mode
|
|
||||||
# for database migrations. You must enable this by adding to build.sbt:
|
|
||||||
#
|
|
||||||
# libraryDependencies += evolutions
|
|
||||||
#
|
|
||||||
play.evolutions {
|
|
||||||
# You can disable evolutions for a specific datasource if necessary
|
|
||||||
#db.default.enabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
## Database Connection Pool
|
|
||||||
# https://www.playframework.com/documentation/latest/SettingsJDBC
|
|
||||||
# ~~~~~
|
|
||||||
# Play doesn't require a JDBC database to run, but you can easily enable one.
|
|
||||||
#
|
|
||||||
# libraryDependencies += jdbc
|
|
||||||
#
|
|
||||||
play.db {
|
|
||||||
# The combination of these two settings results in "db.default" as the
|
|
||||||
# default JDBC pool:
|
|
||||||
#config = "db"
|
|
||||||
#default = "default"
|
|
||||||
|
|
||||||
# Play uses HikariCP as the default connection pool. You can override
|
|
||||||
# settings by changing the prototype:
|
|
||||||
prototype {
|
|
||||||
# Sets a fixed JDBC connection pool size of 50
|
|
||||||
#hikaricp.minimumIdle = 50
|
|
||||||
#hikaricp.maximumPoolSize = 50
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
## JDBC Datasource
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaDatabase
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaDatabase
|
|
||||||
# ~~~~~
|
|
||||||
# Once JDBC datasource is set up, you can work with several different
|
|
||||||
# database options:
|
|
||||||
#
|
|
||||||
# Slick (Scala preferred option): https://www.playframework.com/documentation/latest/PlaySlick
|
|
||||||
# JPA (Java preferred option): https://playframework.com/documentation/latest/JavaJPA
|
|
||||||
# EBean: https://playframework.com/documentation/latest/JavaEbean
|
|
||||||
# Anorm: https://www.playframework.com/documentation/latest/ScalaAnorm
|
|
||||||
#
|
|
||||||
db {
|
|
||||||
# You can declare as many datasources as you want.
|
|
||||||
# By convention, the default datasource is named `default`
|
|
||||||
|
|
||||||
# https://www.playframework.com/documentation/latest/Developing-with-the-H2-Database
|
|
||||||
#default.driver = org.h2.Driver
|
|
||||||
#default.url = "jdbc:h2:mem:play"
|
|
||||||
#default.username = sa
|
|
||||||
#default.password = ""
|
|
||||||
|
|
||||||
# You can turn on SQL logging for any datasource
|
|
||||||
# https://www.playframework.com/documentation/latest/Highlights25#Logging-SQL-statements
|
|
||||||
#default.logSql=true
|
|
||||||
}
|
|
||||||
|
|
|
@ -27,12 +27,6 @@
|
||||||
<logger name="play" level="INFO" />
|
<logger name="play" level="INFO" />
|
||||||
<logger name="application" level="DEBUG" />
|
<logger name="application" level="DEBUG" />
|
||||||
|
|
||||||
<!-- Off these ones as they are annoying, and anyway we manage configuration ourselves -->
|
|
||||||
<logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF" />
|
|
||||||
<logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF" />
|
|
||||||
<logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF" />
|
|
||||||
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />
|
|
||||||
|
|
||||||
<root level="WARN">
|
<root level="WARN">
|
||||||
<appender-ref ref="ASYNCFILE" />
|
<appender-ref ref="ASYNCFILE" />
|
||||||
<appender-ref ref="ASYNCSTDOUT" />
|
<appender-ref ref="ASYNCSTDOUT" />
|
||||||
|
|
|
@ -2,11 +2,14 @@
|
||||||
# This file defines all application routes (Higher priority routes first)
|
# This file defines all application routes (Higher priority routes first)
|
||||||
# ~~~~
|
# ~~~~
|
||||||
|
|
||||||
GET / controllers.StudentController.listStudents()
|
# An example controller showing a sample home page
|
||||||
POST /:id controllers.StudentController.retrieve(id:Int)
|
GET / controllers.HomeController.index
|
||||||
POST / controllers.StudentController.create()
|
GET /baeldung/html controllers.HomeController.applyHtml
|
||||||
PUT / controllers.StudentController.update()
|
GET /baeldung/bad-req controllers.HomeController.badRequestPage
|
||||||
DELETE /:id controllers.StudentController.delete(id:Int)
|
GET /baeldung/not-found controllers.HomeController.notFoundPage
|
||||||
|
GET /baeldung/custom-content-type controllers.HomeController.customContentType
|
||||||
|
GET /baeldung/async controllers.HomeController.asyncOperation
|
||||||
|
GET /baeldung/headers controllers.HomeController.setHeaders
|
||||||
|
|
||||||
# Map static resources from the /public folder to the /assets URL path
|
# Map static resources from the /public folder to the /assets URL path
|
||||||
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
|
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
|
||||||
|
|
Binary file not shown.
|
@ -1,4 +1 @@
|
||||||
#Activator-generated Properties
|
sbt.version=1.2.8
|
||||||
#Wed Sep 07 12:29:40 EAT 2016
|
|
||||||
template.uuid=c373963b-f5ad-433b-8e74-178e7ae25b1c
|
|
||||||
sbt.version=0.13.11
|
|
||||||
|
|
|
@ -1,21 +1,7 @@
|
||||||
// The Play plugin
|
// The Play plugin
|
||||||
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.6")
|
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.3")
|
||||||
|
|
||||||
// Web plugins
|
// Defines scaffolding (found under .g8 folder)
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-coffeescript" % "1.0.0")
|
// http://www.foundweekends.org/giter8/scaffolding.html
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.1.0")
|
// sbt "g8Scaffold form"
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-jshint" % "1.0.3")
|
addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0")
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-rjs" % "1.0.7")
|
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.1.0")
|
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-mocha" % "1.1.0")
|
|
||||||
addSbtPlugin("org.irundaia.sbt" % "sbt-sassify" % "1.4.2")
|
|
||||||
|
|
||||||
// Play enhancer - this automatically generates getters/setters for public fields
|
|
||||||
// and rewrites accessors of these fields to use the getters/setters. Remove this
|
|
||||||
// plugin if you prefer not to have this feature, or disable on a per project
|
|
||||||
// basis using disablePlugins(PlayEnhancer) in your build.sbt
|
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-play-enhancer" % "1.1.0")
|
|
||||||
|
|
||||||
// Play Ebean support, to enable, uncomment this line, and enable in your build.sbt using
|
|
||||||
// enablePlugins(PlayEbean).
|
|
||||||
// addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "1.0.0")
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
if (window.console) {
|
|
||||||
console.log("Welcome to your Play application's JavaScript!");
|
|
||||||
}
|
|
|
@ -1,172 +0,0 @@
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import model.Student;
|
|
||||||
import play.test.*;
|
|
||||||
import static play.test.Helpers.*;
|
|
||||||
|
|
||||||
public class ApplicationLiveTest{
|
|
||||||
private static final String BASE_URL = "http://localhost:9000";
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInServer() throws Exception {
|
|
||||||
TestServer server = testServer(3333);
|
|
||||||
running(server, () -> {
|
|
||||||
try {
|
|
||||||
WSClient ws = play.libs.ws.WS.newClient(3333);
|
|
||||||
CompletionStage<WSResponse> completionStage = ws.url("/").get();
|
|
||||||
WSResponse response = completionStage.toCompletableFuture().get();
|
|
||||||
ws.close();
|
|
||||||
assertEquals(OK, response.getStatus());
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@Test
|
|
||||||
public void whenCreatesRecord_thenCorrect() {
|
|
||||||
Student student = new Student("jody", "west", 50);
|
|
||||||
JSONObject obj = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student)));
|
|
||||||
assertTrue(obj.getBoolean("isSuccessfull"));
|
|
||||||
JSONObject body = obj.getJSONObject("body");
|
|
||||||
assertEquals(student.getAge(), body.getInt("age"));
|
|
||||||
assertEquals(student.getFirstName(), body.getString("firstName"));
|
|
||||||
assertEquals(student.getLastName(), body.getString("lastName"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void whenDeletesCreatedRecord_thenCorrect() {
|
|
||||||
Student student = new Student("Usain", "Bolt", 25);
|
|
||||||
JSONObject ob1 = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student))).getJSONObject("body");
|
|
||||||
int id = ob1.getInt("id");
|
|
||||||
JSONObject obj1 = new JSONObject(makeRequest(BASE_URL + "/" + id, "POST", new JSONObject()));
|
|
||||||
assertTrue(obj1.getBoolean("isSuccessfull"));
|
|
||||||
makeRequest(BASE_URL + "/" + id, "DELETE", null);
|
|
||||||
JSONObject obj2 = new JSONObject(makeRequest(BASE_URL + "/" + id, "POST", new JSONObject()));
|
|
||||||
assertFalse(obj2.getBoolean("isSuccessfull"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void whenUpdatesCreatedRecord_thenCorrect() {
|
|
||||||
Student student = new Student("john", "doe", 50);
|
|
||||||
JSONObject body1 = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student))).getJSONObject("body");
|
|
||||||
assertEquals(student.getAge(), body1.getInt("age"));
|
|
||||||
int newAge = 60;
|
|
||||||
body1.put("age", newAge);
|
|
||||||
JSONObject body2 = new JSONObject(makeRequest(BASE_URL, "PUT", body1)).getJSONObject("body");
|
|
||||||
assertFalse(student.getAge() == body2.getInt("age"));
|
|
||||||
assertTrue(newAge == body2.getInt("age"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void whenGetsAllRecords_thenCorrect() {
|
|
||||||
Student student1 = new Student("jane", "daisy", 50);
|
|
||||||
Student student2 = new Student("john", "daniel", 60);
|
|
||||||
Student student3 = new Student("don", "mason", 55);
|
|
||||||
Student student4 = new Student("scarlet", "ohara", 90);
|
|
||||||
|
|
||||||
makeRequest(BASE_URL, "POST", new JSONObject(student1));
|
|
||||||
makeRequest(BASE_URL, "POST", new JSONObject(student2));
|
|
||||||
makeRequest(BASE_URL, "POST", new JSONObject(student3));
|
|
||||||
makeRequest(BASE_URL, "POST", new JSONObject(student4));
|
|
||||||
|
|
||||||
JSONObject objects = new JSONObject(makeRequest(BASE_URL, "GET", null));
|
|
||||||
assertTrue(objects.getBoolean("isSuccessfull"));
|
|
||||||
JSONArray array = objects.getJSONArray("body");
|
|
||||||
assertTrue(array.length() >= 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String makeRequest(String myUrl, String httpMethod, JSONObject parameters) {
|
|
||||||
|
|
||||||
URL url = null;
|
|
||||||
try {
|
|
||||||
url = new URL(myUrl);
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
HttpURLConnection conn = null;
|
|
||||||
try {
|
|
||||||
|
|
||||||
conn = (HttpURLConnection) url.openConnection();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
conn.setDoInput(true);
|
|
||||||
|
|
||||||
conn.setReadTimeout(10000);
|
|
||||||
|
|
||||||
conn.setRequestProperty("Content-Type", "application/json");
|
|
||||||
DataOutputStream dos = null;
|
|
||||||
int respCode = 0;
|
|
||||||
String inputString = null;
|
|
||||||
try {
|
|
||||||
conn.setRequestMethod(httpMethod);
|
|
||||||
|
|
||||||
if (Arrays.asList("POST", "PUT").contains(httpMethod)) {
|
|
||||||
String params = parameters.toString();
|
|
||||||
|
|
||||||
conn.setDoOutput(true);
|
|
||||||
|
|
||||||
dos = new DataOutputStream(conn.getOutputStream());
|
|
||||||
dos.writeBytes(params);
|
|
||||||
dos.flush();
|
|
||||||
dos.close();
|
|
||||||
}
|
|
||||||
respCode = conn.getResponseCode();
|
|
||||||
if (respCode != 200 && respCode != 201) {
|
|
||||||
String error = inputStreamToString(conn.getErrorStream());
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
inputString = inputStreamToString(conn.getInputStream());
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return inputString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String inputStreamToString(InputStream is) {
|
|
||||||
BufferedReader br = null;
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
String line;
|
|
||||||
try {
|
|
||||||
|
|
||||||
br = new BufferedReader(new InputStreamReader(is));
|
|
||||||
while ((line = br.readLine()) != null) {
|
|
||||||
sb.append(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
if (br != null) {
|
|
||||||
try {
|
|
||||||
br.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
package controllers;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import play.Application;
|
||||||
|
import play.inject.guice.GuiceApplicationBuilder;
|
||||||
|
import play.mvc.Http;
|
||||||
|
import play.mvc.Result;
|
||||||
|
import play.test.WithApplication;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static play.mvc.Http.Status.*;
|
||||||
|
import static play.test.Helpers.GET;
|
||||||
|
import static play.test.Helpers.route;
|
||||||
|
|
||||||
|
public class HomeControllerUnitTest extends WithApplication {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Application provideApplication() {
|
||||||
|
return new GuiceApplicationBuilder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenRequest_whenRootPath_ThenStatusOkay() {
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(GET)
|
||||||
|
.uri("/");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
assertEquals(OK, result.status());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenRequest_whenHtmlPath_ThenStatusOkay() {
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(GET)
|
||||||
|
.uri("/baeldung/html");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
assertEquals(OK, result.status());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenRequest_whenBadRequest_ThenStatusBadRequest() {
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(GET)
|
||||||
|
.uri("/baeldung/bad-req");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
assertEquals(BAD_REQUEST, result.status());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenRequest_whenNotFound_ThenStatusNotFound() {
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(GET)
|
||||||
|
.uri("/baeldung/not-found");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
assertEquals(NOT_FOUND, result.status());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenRequest_whenCustomContentTypePath_ThenContextTypeTextHtml() {
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(GET)
|
||||||
|
.uri("/baeldung/custom-content-type");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
assertTrue(result.contentType().isPresent());
|
||||||
|
assertEquals("text/html", result.contentType().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenRequest_whenAsyncPath_ThenStatusOkay() {
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(GET)
|
||||||
|
.uri("/baeldung/async");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
assertEquals(OK, result.status());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenRequest_whenHeadersPath_ThenCustomHeaderFieldSet() {
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(GET)
|
||||||
|
.uri("/baeldung/headers");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
final Optional<String> headerOptional = result.header("Header-Key");
|
||||||
|
assertTrue(headerOptional.isPresent());
|
||||||
|
assertEquals("Some value", headerOptional.get());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +0,0 @@
|
||||||
This software is licensed under the Apache 2 license, quoted below.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project 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.
|
|
|
@ -1,49 +0,0 @@
|
||||||
This is your new Play application
|
|
||||||
=================================
|
|
||||||
|
|
||||||
This file will be packaged with your application when using `activator dist`.
|
|
||||||
|
|
||||||
There are several demonstration files available in this template.
|
|
||||||
|
|
||||||
Controllers
|
|
||||||
===========
|
|
||||||
|
|
||||||
- HomeController.java:
|
|
||||||
|
|
||||||
Shows how to handle simple HTTP requests.
|
|
||||||
|
|
||||||
- AsyncController.java:
|
|
||||||
|
|
||||||
Shows how to do asynchronous programming when handling a request.
|
|
||||||
|
|
||||||
- CountController.java:
|
|
||||||
|
|
||||||
Shows how to inject a component into a controller and use the component when
|
|
||||||
handling requests.
|
|
||||||
|
|
||||||
Components
|
|
||||||
==========
|
|
||||||
|
|
||||||
- Module.java:
|
|
||||||
|
|
||||||
Shows how to use Guice to bind all the components needed by your application.
|
|
||||||
|
|
||||||
- Counter.java:
|
|
||||||
|
|
||||||
An example of a component that contains state, in this case a simple counter.
|
|
||||||
|
|
||||||
- ApplicationTimer.java:
|
|
||||||
|
|
||||||
An example of a component that starts when the application starts and stops
|
|
||||||
when the application stops.
|
|
||||||
|
|
||||||
Filters
|
|
||||||
=======
|
|
||||||
|
|
||||||
- Filters.java:
|
|
||||||
|
|
||||||
Creates the list of HTTP filters used by your application.
|
|
||||||
|
|
||||||
- ExampleFilter.java
|
|
||||||
|
|
||||||
A simple filter that adds a header to every response.
|
|
|
@ -1,46 +0,0 @@
|
||||||
import javax.inject.*;
|
|
||||||
import play.*;
|
|
||||||
import play.mvc.EssentialFilter;
|
|
||||||
import play.http.HttpFilters;
|
|
||||||
import play.mvc.*;
|
|
||||||
|
|
||||||
import filters.ExampleFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class configures filters that run on every request. This
|
|
||||||
* class is queried by Play to get a list of filters.
|
|
||||||
*
|
|
||||||
* Play will automatically use filters from any class called
|
|
||||||
* <code>Filters</code> that is placed the root package. You can load filters
|
|
||||||
* from a different class by adding a `play.http.filters` setting to
|
|
||||||
* the <code>application.conf</code> configuration file.
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class Filters implements HttpFilters {
|
|
||||||
|
|
||||||
private final Environment env;
|
|
||||||
private final EssentialFilter exampleFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param env Basic environment settings for the current application.
|
|
||||||
* @param exampleFilter A demonstration filter that adds a header to
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
public Filters(Environment env, ExampleFilter exampleFilter) {
|
|
||||||
this.env = env;
|
|
||||||
this.exampleFilter = exampleFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EssentialFilter[] filters() {
|
|
||||||
// Use the example filter if we're running development mode. If
|
|
||||||
// we're running in production or test mode then don't use any
|
|
||||||
// filters at all.
|
|
||||||
if (env.mode().equals(Mode.DEV)) {
|
|
||||||
return new EssentialFilter[] { exampleFilter };
|
|
||||||
} else {
|
|
||||||
return new EssentialFilter[] {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
import com.google.inject.AbstractModule;
|
|
||||||
import java.time.Clock;
|
|
||||||
|
|
||||||
import services.ApplicationTimer;
|
|
||||||
import services.AtomicCounter;
|
|
||||||
import services.Counter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is a Guice module that tells Guice how to bind several
|
|
||||||
* different types. This Guice module is created when the Play
|
|
||||||
* application starts.
|
|
||||||
*
|
|
||||||
* Play will automatically use any class called `Module` that is in
|
|
||||||
* the root package. You can create modules in other locations by
|
|
||||||
* adding `play.modules.enabled` settings to the `application.conf`
|
|
||||||
* configuration file.
|
|
||||||
*/
|
|
||||||
public class Module extends AbstractModule {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configure() {
|
|
||||||
// Use the system clock as the default implementation of Clock
|
|
||||||
bind(Clock.class).toInstance(Clock.systemDefaultZone());
|
|
||||||
// Ask Guice to create an instance of ApplicationTimer when the
|
|
||||||
// application starts.
|
|
||||||
bind(ApplicationTimer.class).asEagerSingleton();
|
|
||||||
// Set AtomicCounter as the implementation for Counter.
|
|
||||||
bind(Counter.class).to(AtomicCounter.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,8 +1,13 @@
|
||||||
package controllers;
|
package controllers;
|
||||||
|
|
||||||
|
import play.libs.concurrent.HttpExecutionContext;
|
||||||
import play.mvc.*;
|
import play.mvc.*;
|
||||||
|
import play.twirl.api.Html;
|
||||||
|
|
||||||
import views.html.*;
|
import javax.inject.Inject;
|
||||||
|
import java.util.concurrent.CompletionStage;
|
||||||
|
|
||||||
|
import static java.util.concurrent.CompletableFuture.supplyAsync;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller contains an action to handle HTTP requests
|
* This controller contains an action to handle HTTP requests
|
||||||
|
@ -16,18 +21,33 @@ public class HomeController extends Controller {
|
||||||
* this method will be called when the application receives a
|
* this method will be called when the application receives a
|
||||||
* <code>GET</code> request with a path of <code>/</code>.
|
* <code>GET</code> request with a path of <code>/</code>.
|
||||||
*/
|
*/
|
||||||
public Result index(String author,int id) {
|
public Result index() {
|
||||||
return ok("Routing in Play by:"+author+" ID:"+id);
|
return ok(views.html.index.render());
|
||||||
}
|
|
||||||
public Result greet(String name,int age) {
|
|
||||||
return ok("Hello "+name+", you are "+age+" years old");
|
|
||||||
}
|
|
||||||
public Result introduceMe(String data) {
|
|
||||||
String[] clientData=data.split(",");
|
|
||||||
return ok("Your name is "+clientData[0]+", you are "+clientData[1]+" years old");
|
|
||||||
}
|
|
||||||
public Result squareMe(Long num) {
|
|
||||||
return ok(num+" Squared is "+(num*num));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Result writer(String author) {
|
||||||
|
return ok("Routing in Play by " + author);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result viewUser(String userId) {
|
||||||
|
final String response = String.format("Got user id {} in request.", userId);
|
||||||
|
return ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result greet(String name, int age) {
|
||||||
|
return ok("Hello " + name + ", you are " + age + " years old");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result squareMe(Long num) {
|
||||||
|
return ok(num + " Squared is " + (num * num));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result writer(String author, int id) {
|
||||||
|
return ok("Routing in Play by: " + author + " ID: " + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result introduceMe(String data) {
|
||||||
|
String[] clientData = data.split(",");
|
||||||
|
return ok("Your name is " + clientData[0] + ", you are " + clientData[1] + " years old");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
package filters;
|
|
||||||
|
|
||||||
import akka.stream.Materializer;
|
|
||||||
import java.util.concurrent.CompletionStage;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import javax.inject.*;
|
|
||||||
import play.mvc.*;
|
|
||||||
import play.mvc.Http.RequestHeader;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a simple filter that adds a header to all requests. It's
|
|
||||||
* added to the application's list of filters by the
|
|
||||||
* {@link Filters} class.
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class ExampleFilter extends Filter {
|
|
||||||
|
|
||||||
private final Executor exec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mat This object is needed to handle streaming of requests
|
|
||||||
* and responses.
|
|
||||||
* @param exec This class is needed to execute code asynchronously.
|
|
||||||
* It is used below by the <code>thenAsyncApply</code> method.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
public ExampleFilter(Materializer mat, Executor exec) {
|
|
||||||
super(mat);
|
|
||||||
this.exec = exec;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompletionStage<Result> apply(
|
|
||||||
Function<RequestHeader, CompletionStage<Result>> next,
|
|
||||||
RequestHeader requestHeader) {
|
|
||||||
|
|
||||||
return next.apply(requestHeader).thenApplyAsync(
|
|
||||||
result -> result.withHeader("X-ExampleFilter", "foo"),
|
|
||||||
exec
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
package services;
|
|
||||||
|
|
||||||
import java.time.Clock;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import javax.inject.*;
|
|
||||||
import play.Logger;
|
|
||||||
import play.inject.ApplicationLifecycle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class demonstrates how to run code when the
|
|
||||||
* application starts and stops. It starts a timer when the
|
|
||||||
* application starts. When the application stops it prints out how
|
|
||||||
* long the application was running for.
|
|
||||||
*
|
|
||||||
* This class is registered for Guice dependency injection in the
|
|
||||||
* {@link Module} class. We want the class to start when the application
|
|
||||||
* starts, so it is registered as an "eager singleton". See the code
|
|
||||||
* in the {@link Module} class to see how this happens.
|
|
||||||
*
|
|
||||||
* This class needs to run code when the server stops. It uses the
|
|
||||||
* application's {@link ApplicationLifecycle} to register a stop hook.
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class ApplicationTimer {
|
|
||||||
|
|
||||||
private final Clock clock;
|
|
||||||
private final ApplicationLifecycle appLifecycle;
|
|
||||||
private final Instant start;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public ApplicationTimer(Clock clock, ApplicationLifecycle appLifecycle) {
|
|
||||||
this.clock = clock;
|
|
||||||
this.appLifecycle = appLifecycle;
|
|
||||||
// This code is called when the application starts.
|
|
||||||
start = clock.instant();
|
|
||||||
Logger.info("ApplicationTimer demo: Starting application at " + start);
|
|
||||||
|
|
||||||
// When the application starts, register a stop hook with the
|
|
||||||
// ApplicationLifecycle object. The code inside the stop hook will
|
|
||||||
// be run when the application stops.
|
|
||||||
appLifecycle.addStopHook(() -> {
|
|
||||||
Instant stop = clock.instant();
|
|
||||||
Long runningTime = stop.getEpochSecond() - start.getEpochSecond();
|
|
||||||
Logger.info("ApplicationTimer demo: Stopping application at " + clock.instant() + " after " + runningTime + "s.");
|
|
||||||
return CompletableFuture.completedFuture(null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package services;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is a concrete implementation of the {@link Counter} trait.
|
|
||||||
* It is configured for Guice dependency injection in the {@link Module}
|
|
||||||
* class.
|
|
||||||
*
|
|
||||||
* This class has a {@link Singleton} annotation because we need to make
|
|
||||||
* sure we only use one counter per application. Without this
|
|
||||||
* annotation we would get a new instance every time a {@link Counter} is
|
|
||||||
* injected.
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class AtomicCounter implements Counter {
|
|
||||||
|
|
||||||
private final AtomicInteger atomicCounter = new AtomicInteger();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int nextCount() {
|
|
||||||
return atomicCounter.getAndIncrement();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package services;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This interface demonstrates how to create a component that is injected
|
|
||||||
* into a controller. The interface represents a counter that returns a
|
|
||||||
* incremented number each time it is called.
|
|
||||||
*
|
|
||||||
* The {@link Modules} class binds this interface to the
|
|
||||||
* {@link AtomicCounter} implementation.
|
|
||||||
*/
|
|
||||||
public interface Counter {
|
|
||||||
int nextCount();
|
|
||||||
}
|
|
|
@ -1,20 +1,5 @@
|
||||||
@*
|
@()
|
||||||
* This template takes a single argument, a String containing a
|
|
||||||
* message to display.
|
|
||||||
*@
|
|
||||||
@(message: String)
|
|
||||||
|
|
||||||
@*
|
|
||||||
* Call the `main` template with two arguments. The first
|
|
||||||
* argument is a `String` with the title of the page, the second
|
|
||||||
* argument is an `Html` object containing the body of the page.
|
|
||||||
*@
|
|
||||||
@main("Welcome to Play") {
|
@main("Welcome to Play") {
|
||||||
|
<h1>Welcome to Play!</h1>
|
||||||
@*
|
|
||||||
* Get an `Html` object by calling the built-in Play welcome
|
|
||||||
* template and passing a `String` message.
|
|
||||||
*@
|
|
||||||
@play20.welcome(message, style = "Java")
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,12 @@
|
||||||
<title>@title</title>
|
<title>@title</title>
|
||||||
<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
|
<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
|
||||||
<link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
|
<link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
|
||||||
<script src="@routes.Assets.versioned("javascripts/hello.js")" type="text/javascript"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@* And here's where we render the `Html` object containing
|
@* And here's where we render the `Html` object containing
|
||||||
* the page content. *@
|
* the page content. *@
|
||||||
@content
|
@content
|
||||||
|
|
||||||
|
<script src="@routes.Assets.versioned("javascripts/main.js")" type="text/javascript"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,397 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
### ------------------------------- ###
|
|
||||||
### Helper methods for BASH scripts ###
|
|
||||||
### ------------------------------- ###
|
|
||||||
|
|
||||||
realpath () {
|
|
||||||
(
|
|
||||||
TARGET_FILE="$1"
|
|
||||||
FIX_CYGPATH="$2"
|
|
||||||
|
|
||||||
cd "$(dirname "$TARGET_FILE")"
|
|
||||||
TARGET_FILE=$(basename "$TARGET_FILE")
|
|
||||||
|
|
||||||
COUNT=0
|
|
||||||
while [ -L "$TARGET_FILE" -a $COUNT -lt 100 ]
|
|
||||||
do
|
|
||||||
TARGET_FILE=$(readlink "$TARGET_FILE")
|
|
||||||
cd "$(dirname "$TARGET_FILE")"
|
|
||||||
TARGET_FILE=$(basename "$TARGET_FILE")
|
|
||||||
COUNT=$(($COUNT + 1))
|
|
||||||
done
|
|
||||||
|
|
||||||
# make sure we grab the actual windows path, instead of cygwin's path.
|
|
||||||
if [[ "x$FIX_CYGPATH" != "x" ]]; then
|
|
||||||
echo "$(cygwinpath "$(pwd -P)/$TARGET_FILE")"
|
|
||||||
else
|
|
||||||
echo "$(pwd -P)/$TARGET_FILE"
|
|
||||||
fi
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Uses uname to detect if we're in the odd cygwin environment.
|
|
||||||
is_cygwin() {
|
|
||||||
local os=$(uname -s)
|
|
||||||
case "$os" in
|
|
||||||
CYGWIN*) return 0 ;;
|
|
||||||
*) return 1 ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO - Use nicer bash-isms here.
|
|
||||||
CYGWIN_FLAG=$(if is_cygwin; then echo true; else echo false; fi)
|
|
||||||
|
|
||||||
|
|
||||||
# This can fix cygwin style /cygdrive paths so we get the
|
|
||||||
# windows style paths.
|
|
||||||
cygwinpath() {
|
|
||||||
local file="$1"
|
|
||||||
if [[ "$CYGWIN_FLAG" == "true" ]]; then
|
|
||||||
echo $(cygpath -w $file)
|
|
||||||
else
|
|
||||||
echo $file
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Make something URI friendly
|
|
||||||
make_url() {
|
|
||||||
url="$1"
|
|
||||||
local nospaces=${url// /%20}
|
|
||||||
if is_cygwin; then
|
|
||||||
echo "/${nospaces//\\//}"
|
|
||||||
else
|
|
||||||
echo "$nospaces"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
declare -a residual_args
|
|
||||||
declare -a java_args
|
|
||||||
declare -a scalac_args
|
|
||||||
declare -a sbt_commands
|
|
||||||
declare java_cmd=java
|
|
||||||
declare java_version
|
|
||||||
declare -r real_script_path="$(realpath "$0")"
|
|
||||||
declare -r sbt_home="$(realpath "$(dirname "$(dirname "$real_script_path")")")"
|
|
||||||
declare -r sbt_bin_dir="$(dirname "$real_script_path")"
|
|
||||||
declare -r app_version="1.3.10"
|
|
||||||
|
|
||||||
declare -r script_name=activator
|
|
||||||
declare -r java_opts=( "${ACTIVATOR_OPTS[@]}" "${SBT_OPTS[@]}" "${JAVA_OPTS[@]}" "${java_opts[@]}" )
|
|
||||||
userhome="$HOME"
|
|
||||||
if is_cygwin; then
|
|
||||||
# cygwin sets home to something f-d up, set to real windows homedir
|
|
||||||
userhome="$USERPROFILE"
|
|
||||||
fi
|
|
||||||
declare -r activator_user_home_dir="${userhome}/.activator"
|
|
||||||
declare -r java_opts_config_home="${activator_user_home_dir}/activatorconfig.txt"
|
|
||||||
declare -r java_opts_config_version="${activator_user_home_dir}/${app_version}/activatorconfig.txt"
|
|
||||||
|
|
||||||
echoerr () {
|
|
||||||
echo 1>&2 "$@"
|
|
||||||
}
|
|
||||||
vlog () {
|
|
||||||
[[ $verbose || $debug ]] && echoerr "$@"
|
|
||||||
}
|
|
||||||
dlog () {
|
|
||||||
[[ $debug ]] && echoerr "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
jar_file () {
|
|
||||||
echo "$(cygwinpath "${sbt_home}/libexec/activator-launch-${app_version}.jar")"
|
|
||||||
}
|
|
||||||
|
|
||||||
acquire_sbt_jar () {
|
|
||||||
sbt_jar="$(jar_file)"
|
|
||||||
|
|
||||||
if [[ ! -f "$sbt_jar" ]]; then
|
|
||||||
echoerr "Could not find launcher jar: $sbt_jar"
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
execRunner () {
|
|
||||||
# print the arguments one to a line, quoting any containing spaces
|
|
||||||
[[ $verbose || $debug ]] && echo "# Executing command line:" && {
|
|
||||||
for arg; do
|
|
||||||
if printf "%s\n" "$arg" | grep -q ' '; then
|
|
||||||
printf "\"%s\"\n" "$arg"
|
|
||||||
else
|
|
||||||
printf "%s\n" "$arg"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# THis used to be exec, but we loose the ability to re-hook stty then
|
|
||||||
# for cygwin... Maybe we should flag the feature here...
|
|
||||||
"$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
addJava () {
|
|
||||||
dlog "[addJava] arg = '$1'"
|
|
||||||
java_args=( "${java_args[@]}" "$1" )
|
|
||||||
}
|
|
||||||
addSbt () {
|
|
||||||
dlog "[addSbt] arg = '$1'"
|
|
||||||
sbt_commands=( "${sbt_commands[@]}" "$1" )
|
|
||||||
}
|
|
||||||
addResidual () {
|
|
||||||
dlog "[residual] arg = '$1'"
|
|
||||||
residual_args=( "${residual_args[@]}" "$1" )
|
|
||||||
}
|
|
||||||
addDebugger () {
|
|
||||||
addJava "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
get_mem_opts () {
|
|
||||||
# if we detect any of these settings in ${JAVA_OPTS} we need to NOT output our settings.
|
|
||||||
# The reason is the Xms/Xmx, if they don't line up, cause errors.
|
|
||||||
if [[ "${JAVA_OPTS}" == *-Xmx* ]] || [[ "${JAVA_OPTS}" == *-Xms* ]] || [[ "${JAVA_OPTS}" == *-XX:MaxPermSize* ]] || [[ "${JAVA_OPTS}" == *-XX:MaxMetaspaceSize* ]] || [[ "${JAVA_OPTS}" == *-XX:ReservedCodeCacheSize* ]]; then
|
|
||||||
echo ""
|
|
||||||
else
|
|
||||||
# a ham-fisted attempt to move some memory settings in concert
|
|
||||||
# so they need not be messed around with individually.
|
|
||||||
local mem=${1:-1024}
|
|
||||||
local codecache=$(( $mem / 8 ))
|
|
||||||
(( $codecache > 128 )) || codecache=128
|
|
||||||
(( $codecache < 512 )) || codecache=512
|
|
||||||
local class_metadata_size=$(( $codecache * 2 ))
|
|
||||||
local class_metadata_opt=$([[ "$java_version" < "1.8" ]] && echo "MaxPermSize" || echo "MaxMetaspaceSize")
|
|
||||||
|
|
||||||
echo "-Xms${mem}m -Xmx${mem}m -XX:ReservedCodeCacheSize=${codecache}m -XX:${class_metadata_opt}=${class_metadata_size}m"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
require_arg () {
|
|
||||||
local type="$1"
|
|
||||||
local opt="$2"
|
|
||||||
local arg="$3"
|
|
||||||
if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then
|
|
||||||
echo "$opt requires <$type> argument"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
is_function_defined() {
|
|
||||||
declare -f "$1" > /dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
# If we're *not* running in a terminal, and we don't have any arguments, then we need to add the 'ui' parameter
|
|
||||||
detect_terminal_for_ui() {
|
|
||||||
[[ ! -t 0 ]] && [[ "${#residual_args}" == "0" ]] && {
|
|
||||||
addResidual "ui"
|
|
||||||
}
|
|
||||||
# SPECIAL TEST FOR MAC
|
|
||||||
[[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]] && [[ "${#residual_args}" == "0" ]] && {
|
|
||||||
echo "Detected MAC OSX launched script...."
|
|
||||||
echo "Swapping to UI"
|
|
||||||
addResidual "ui"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
process_args () {
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
-h|-help) usage; exit 1 ;;
|
|
||||||
-v|-verbose) verbose=1 && shift ;;
|
|
||||||
-d|-debug) debug=1 && shift ;;
|
|
||||||
|
|
||||||
-ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;;
|
|
||||||
-mem) require_arg integer "$1" "$2" && sbt_mem="$2" && shift 2 ;;
|
|
||||||
-jvm-debug) require_arg port "$1" "$2" && addDebugger $2 && shift 2 ;;
|
|
||||||
-batch) exec </dev/null && shift ;;
|
|
||||||
|
|
||||||
-sbt-jar) require_arg path "$1" "$2" && sbt_jar="$2" && shift 2 ;;
|
|
||||||
-sbt-version) require_arg version "$1" "$2" && sbt_version="$2" && shift 2 ;;
|
|
||||||
-java-home) require_arg path "$1" "$2" && java_cmd="$2/bin/java" && shift 2 ;;
|
|
||||||
|
|
||||||
-D*) addJava "$1" && shift ;;
|
|
||||||
-J*) addJava "${1:2}" && shift ;;
|
|
||||||
*) addResidual "$1" && shift ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
is_function_defined process_my_args && {
|
|
||||||
myargs=("${residual_args[@]}")
|
|
||||||
residual_args=()
|
|
||||||
process_my_args "${myargs[@]}"
|
|
||||||
}
|
|
||||||
|
|
||||||
java_version=$("$java_cmd" -Xmx512M -version 2>&1 | awk -F '"' '/version/ {print $2}')
|
|
||||||
vlog "[process_args] java_version = '$java_version'"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Detect that we have java installed.
|
|
||||||
checkJava() {
|
|
||||||
local required_version="$1"
|
|
||||||
# Now check to see if it's a good enough version
|
|
||||||
if [[ "$java_version" == "" ]]; then
|
|
||||||
echo
|
|
||||||
echo No java installations was detected.
|
|
||||||
echo Please go to http://www.java.com/getjava/ and download
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
elif [[ ! "$java_version" > "$required_version" ]]; then
|
|
||||||
echo
|
|
||||||
echo The java installation you have is not up to date
|
|
||||||
echo $script_name requires at least version $required_version+, you have
|
|
||||||
echo version $java_version
|
|
||||||
echo
|
|
||||||
echo Please go to http://www.java.com/getjava/ and download
|
|
||||||
echo a valid Java Runtime and install before running $script_name.
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
run() {
|
|
||||||
# no jar? download it.
|
|
||||||
[[ -f "$sbt_jar" ]] || acquire_sbt_jar "$sbt_version" || {
|
|
||||||
# still no jar? uh-oh.
|
|
||||||
echo "Download failed. Obtain the sbt-launch.jar manually and place it at $sbt_jar"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# process the combined args, then reset "$@" to the residuals
|
|
||||||
process_args "$@"
|
|
||||||
detect_terminal_for_ui
|
|
||||||
set -- "${residual_args[@]}"
|
|
||||||
argumentCount=$#
|
|
||||||
|
|
||||||
# TODO - java check should be configurable...
|
|
||||||
checkJava "1.6"
|
|
||||||
|
|
||||||
#If we're in cygwin, we should use the windows config, and terminal hacks
|
|
||||||
if [[ "$CYGWIN_FLAG" == "true" ]]; then
|
|
||||||
stty -icanon min 1 -echo > /dev/null 2>&1
|
|
||||||
addJava "-Djline.terminal=jline.UnixTerminal"
|
|
||||||
addJava "-Dsbt.cygwin=true"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# run sbt
|
|
||||||
execRunner "$java_cmd" \
|
|
||||||
"-Dactivator.home=$(make_url "$sbt_home")" \
|
|
||||||
${SBT_OPTS:-$default_sbt_opts} \
|
|
||||||
$(get_mem_opts $sbt_mem) \
|
|
||||||
${JAVA_OPTS} \
|
|
||||||
${java_args[@]} \
|
|
||||||
-jar "$sbt_jar" \
|
|
||||||
"${sbt_commands[@]}" \
|
|
||||||
"${residual_args[@]}"
|
|
||||||
|
|
||||||
exit_code=$?
|
|
||||||
|
|
||||||
# Clean up the terminal from cygwin hacks.
|
|
||||||
if [[ "$CYGWIN_FLAG" == "true" ]]; then
|
|
||||||
stty icanon echo > /dev/null 2>&1
|
|
||||||
fi
|
|
||||||
exit $exit_code
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy"
|
|
||||||
declare -r sbt_opts_file=".sbtopts"
|
|
||||||
declare -r etc_sbt_opts_file="${sbt_home}/conf/sbtopts"
|
|
||||||
declare -r win_sbt_opts_file="${sbt_home}/conf/sbtconfig.txt"
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<EOM
|
|
||||||
Usage: $script_name [options]
|
|
||||||
|
|
||||||
Command:
|
|
||||||
ui Start the Activator UI
|
|
||||||
new [name] [template-id] Create a new project with [name] using template [template-id]
|
|
||||||
list-templates Print all available template names
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h | -help print this message
|
|
||||||
-v | -verbose this runner is chattier
|
|
||||||
-d | -debug set sbt log level to debug
|
|
||||||
-no-colors disable ANSI color codes
|
|
||||||
-sbt-create start sbt even if current directory contains no sbt project
|
|
||||||
-sbt-dir <path> path to global settings/plugins directory (default: ~/.sbt)
|
|
||||||
-sbt-boot <path> path to shared boot directory (default: ~/.sbt/boot in 0.11 series)
|
|
||||||
-ivy <path> path to local Ivy repository (default: ~/.ivy2)
|
|
||||||
-mem <integer> set memory options (default: $sbt_mem, which is $(get_mem_opts $sbt_mem))
|
|
||||||
-no-share use all local caches; no sharing
|
|
||||||
-no-global uses global caches, but does not use global ~/.sbt directory.
|
|
||||||
-jvm-debug <port> Turn on JVM debugging, open at the given port.
|
|
||||||
-batch Disable interactive mode
|
|
||||||
|
|
||||||
# sbt version (default: from project/build.properties if present, else latest release)
|
|
||||||
-sbt-version <version> use the specified version of sbt
|
|
||||||
-sbt-jar <path> use the specified jar as the sbt launcher
|
|
||||||
-sbt-rc use an RC version of sbt
|
|
||||||
-sbt-snapshot use a snapshot version of sbt
|
|
||||||
|
|
||||||
# java version (default: java from PATH, currently $(java -version 2>&1 | grep version))
|
|
||||||
-java-home <path> alternate JAVA_HOME
|
|
||||||
|
|
||||||
# jvm options and output control
|
|
||||||
JAVA_OPTS environment variable, if unset uses "$java_opts"
|
|
||||||
SBT_OPTS environment variable, if unset uses "$default_sbt_opts"
|
|
||||||
ACTIVATOR_OPTS Environment variable, if unset uses ""
|
|
||||||
.sbtopts if this file exists in the current directory, it is
|
|
||||||
prepended to the runner args
|
|
||||||
/etc/sbt/sbtopts if this file exists, it is prepended to the runner args
|
|
||||||
-Dkey=val pass -Dkey=val directly to the java runtime
|
|
||||||
-J-X pass option -X directly to the java runtime
|
|
||||||
(-J is stripped)
|
|
||||||
-S-X add -X to sbt's scalacOptions (-S is stripped)
|
|
||||||
|
|
||||||
In the case of duplicated or conflicting options, the order above
|
|
||||||
shows precedence: JAVA_OPTS lowest, command line options highest.
|
|
||||||
EOM
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
process_my_args () {
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
-no-colors) addJava "-Dsbt.log.noformat=true" && shift ;;
|
|
||||||
-no-share) addJava "$noshare_opts" && shift ;;
|
|
||||||
-no-global) addJava "-Dsbt.global.base=$(pwd)/project/.sbtboot" && shift ;;
|
|
||||||
-sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;;
|
|
||||||
-sbt-dir) require_arg path "$1" "$2" && addJava "-Dsbt.global.base=$2" && shift 2 ;;
|
|
||||||
-debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;;
|
|
||||||
-batch) exec </dev/null && shift ;;
|
|
||||||
|
|
||||||
-sbt-create) sbt_create=true && shift ;;
|
|
||||||
|
|
||||||
*) addResidual "$1" && shift ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Now, ensure sbt version is used.
|
|
||||||
[[ "${sbt_version}XXX" != "XXX" ]] && addJava "-Dsbt.version=$sbt_version"
|
|
||||||
}
|
|
||||||
|
|
||||||
loadConfigFile() {
|
|
||||||
cat "$1" | sed '/^\#/d' | while read line; do
|
|
||||||
eval echo $line
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO - Pull in config based on operating system... (MSYS + cygwin should pull in txt file).
|
|
||||||
# Here we pull in the global settings configuration.
|
|
||||||
[[ -f "$etc_sbt_opts_file" ]] && set -- $(loadConfigFile "$etc_sbt_opts_file") "$@"
|
|
||||||
# -- Windows behavior stub'd
|
|
||||||
# JAVA_OPTS=$(cat "$WDIR/sbtconfig.txt" | sed -e 's/\r//g' -e 's/^#.*$//g' | sed ':a;N;$!ba;s/\n/ /g')
|
|
||||||
|
|
||||||
|
|
||||||
# Pull in the project-level config file, if it exists.
|
|
||||||
[[ -f "$sbt_opts_file" ]] && set -- $(loadConfigFile "$sbt_opts_file") "$@"
|
|
||||||
|
|
||||||
# if configuration files exist, prepend their contents to the java args so it can be processed by this runner
|
|
||||||
# a "versioned" config trumps one on the top level
|
|
||||||
if [[ -f "$java_opts_config_version" ]]; then
|
|
||||||
addConfigOpts $(loadConfigFile "$java_opts_config_version")
|
|
||||||
elif [[ -f "$java_opts_config_home" ]]; then
|
|
||||||
addConfigOpts $(loadConfigFile "$java_opts_config_home")
|
|
||||||
fi
|
|
||||||
|
|
||||||
run "$@"
|
|
|
@ -1,248 +0,0 @@
|
||||||
@REM activator launcher script
|
|
||||||
@REM
|
|
||||||
@REM Environment:
|
|
||||||
@REM In order for Activator to work you must have Java available on the classpath
|
|
||||||
@REM JAVA_HOME - location of a JDK home dir (optional if java on path)
|
|
||||||
@REM CFG_OPTS - JVM options (optional)
|
|
||||||
@REM Configuration:
|
|
||||||
@REM activatorconfig.txt found in the ACTIVATOR_HOME or ACTIVATOR_HOME/ACTIVATOR_VERSION
|
|
||||||
@setlocal enabledelayedexpansion
|
|
||||||
|
|
||||||
@echo off
|
|
||||||
|
|
||||||
set "var1=%~1"
|
|
||||||
if defined var1 (
|
|
||||||
if "%var1%"=="help" (
|
|
||||||
echo.
|
|
||||||
echo Usage activator [options] [command]
|
|
||||||
echo.
|
|
||||||
echo Commands:
|
|
||||||
echo ui Start the Activator UI
|
|
||||||
echo new [name] [template-id] Create a new project with [name] using template [template-id]
|
|
||||||
echo list-templates Print all available template names
|
|
||||||
echo help Print this message
|
|
||||||
echo.
|
|
||||||
echo Options:
|
|
||||||
echo -jvm-debug [port] Turn on JVM debugging, open at the given port. Defaults to 9999 if no port given.
|
|
||||||
echo.
|
|
||||||
echo Environment variables ^(read from context^):
|
|
||||||
echo JAVA_OPTS Environment variable, if unset uses ""
|
|
||||||
echo SBT_OPTS Environment variable, if unset uses ""
|
|
||||||
echo ACTIVATOR_OPTS Environment variable, if unset uses ""
|
|
||||||
echo.
|
|
||||||
echo Please note that in order for Activator to work you must have Java available on the classpath
|
|
||||||
echo.
|
|
||||||
goto :end
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
@REM determine ACTIVATOR_HOME environment variable
|
|
||||||
set BIN_DIRECTORY=%~dp0
|
|
||||||
set BIN_DIRECTORY=%BIN_DIRECTORY:~0,-1%
|
|
||||||
for %%d in (%BIN_DIRECTORY%) do set ACTIVATOR_HOME=%%~dpd
|
|
||||||
set ACTIVATOR_HOME=%ACTIVATOR_HOME:~0,-1%
|
|
||||||
|
|
||||||
echo ACTIVATOR_HOME=%ACTIVATOR_HOME%
|
|
||||||
|
|
||||||
set ERROR_CODE=0
|
|
||||||
set APP_VERSION=1.3.10
|
|
||||||
set ACTIVATOR_LAUNCH_JAR=activator-launch-%APP_VERSION%.jar
|
|
||||||
|
|
||||||
rem Detect if we were double clicked, although theoretically A user could
|
|
||||||
rem manually run cmd /c
|
|
||||||
for %%x in (%cmdcmdline%) do if %%~x==/c set DOUBLECLICKED=1
|
|
||||||
|
|
||||||
set SBT_HOME=%BIN_DIRECTORY
|
|
||||||
|
|
||||||
rem Detect if we were double clicked, although theoretically A user could
|
|
||||||
rem manually run cmd /c
|
|
||||||
for %%x in (%cmdcmdline%) do if %%~x==/c set DOUBLECLICKED=1
|
|
||||||
|
|
||||||
rem FIRST we load the config file of extra options.
|
|
||||||
set FN=%SBT_HOME%\..\conf\sbtconfig.txt
|
|
||||||
set CFG_OPTS=
|
|
||||||
FOR /F "tokens=* eol=# usebackq delims=" %%i IN ("%FN%") DO (
|
|
||||||
set DO_NOT_REUSE_ME=%%i
|
|
||||||
rem ZOMG (Part #2) WE use !! here to delay the expansion of
|
|
||||||
rem CFG_OPTS, otherwise it remains "" for this loop.
|
|
||||||
set CFG_OPTS=!CFG_OPTS! !DO_NOT_REUSE_ME!
|
|
||||||
)
|
|
||||||
|
|
||||||
rem FIRST we load a config file of extra options (if there is one)
|
|
||||||
set "CFG_FILE_HOME=%UserProfile%\.activator\activatorconfig.txt"
|
|
||||||
set "CFG_FILE_VERSION=%UserProfile%\.activator\%APP_VERSION%\activatorconfig.txt"
|
|
||||||
if exist %CFG_FILE_VERSION% (
|
|
||||||
FOR /F "tokens=* eol=# usebackq delims=" %%i IN ("%CFG_FILE_VERSION%") DO (
|
|
||||||
set DO_NOT_REUSE_ME=%%i
|
|
||||||
rem ZOMG (Part #2) WE use !! here to delay the expansion of
|
|
||||||
rem CFG_OPTS, otherwise it remains "" for this loop.
|
|
||||||
set CFG_OPTS=!CFG_OPTS! !DO_NOT_REUSE_ME!
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if "%CFG_OPTS%"=="" (
|
|
||||||
if exist %CFG_FILE_HOME% (
|
|
||||||
FOR /F "tokens=* eol=# usebackq delims=" %%i IN ("%CFG_FILE_HOME%") DO (
|
|
||||||
set DO_NOT_REUSE_ME=%%i
|
|
||||||
rem ZOMG (Part #2) WE use !! here to delay the expansion of
|
|
||||||
rem CFG_OPTS, otherwise it remains "" for this loop.
|
|
||||||
set CFG_OPTS=!CFG_OPTS! !DO_NOT_REUSE_ME!
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
rem We use the value of the JAVACMD environment variable if defined
|
|
||||||
set _JAVACMD=%JAVACMD%
|
|
||||||
|
|
||||||
if "%_JAVACMD%"=="" (
|
|
||||||
if not "%JAVA_HOME%"=="" (
|
|
||||||
if exist "%JAVA_HOME%\bin\java.exe" set "_JAVACMD=%JAVA_HOME%\bin\java.exe"
|
|
||||||
|
|
||||||
rem if there is a java home set we make sure it is the first picked up when invoking 'java'
|
|
||||||
SET "PATH=%JAVA_HOME%\bin;%PATH%"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%_JAVACMD%"=="" set _JAVACMD=java
|
|
||||||
|
|
||||||
rem Detect if this java is ok to use.
|
|
||||||
for /F %%j in ('"%_JAVACMD%" -version 2^>^&1') do (
|
|
||||||
if %%~j==java set JAVAINSTALLED=1
|
|
||||||
if %%~j==openjdk set JAVAINSTALLED=1
|
|
||||||
)
|
|
||||||
|
|
||||||
rem Detect the same thing about javac
|
|
||||||
if "%_JAVACCMD%"=="" (
|
|
||||||
if not "%JAVA_HOME%"=="" (
|
|
||||||
if exist "%JAVA_HOME%\bin\javac.exe" set "_JAVACCMD=%JAVA_HOME%\bin\javac.exe"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if "%_JAVACCMD%"=="" set _JAVACCMD=javac
|
|
||||||
for /F %%j in ('"%_JAVACCMD%" -version 2^>^&1') do (
|
|
||||||
if %%~j==javac set JAVACINSTALLED=1
|
|
||||||
)
|
|
||||||
|
|
||||||
rem BAT has no logical or, so we do it OLD SCHOOL! Oppan Redmond Style
|
|
||||||
set JAVAOK=true
|
|
||||||
if not defined JAVAINSTALLED set JAVAOK=false
|
|
||||||
if not defined JAVACINSTALLED set JAVAOK=false
|
|
||||||
|
|
||||||
if "%JAVAOK%"=="false" (
|
|
||||||
echo.
|
|
||||||
echo A Java JDK is not installed or can't be found.
|
|
||||||
if not "%JAVA_HOME%"=="" (
|
|
||||||
echo JAVA_HOME = "%JAVA_HOME%"
|
|
||||||
)
|
|
||||||
echo.
|
|
||||||
echo Please go to
|
|
||||||
echo http://www.oracle.com/technetwork/java/javase/downloads/index.html
|
|
||||||
echo and download a valid Java JDK and install before running Activator.
|
|
||||||
echo.
|
|
||||||
echo If you think this message is in error, please check
|
|
||||||
echo your environment variables to see if "java.exe" and "javac.exe" are
|
|
||||||
echo available via JAVA_HOME or PATH.
|
|
||||||
echo.
|
|
||||||
if defined DOUBLECLICKED pause
|
|
||||||
exit /B 1
|
|
||||||
)
|
|
||||||
|
|
||||||
rem Check what Java version is being used to determine what memory options to use
|
|
||||||
for /f "tokens=3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do (
|
|
||||||
set JAVA_VERSION=%%g
|
|
||||||
)
|
|
||||||
|
|
||||||
rem Strips away the " characters
|
|
||||||
set JAVA_VERSION=%JAVA_VERSION:"=%
|
|
||||||
|
|
||||||
rem TODO Check if there are existing mem settings in JAVA_OPTS/CFG_OPTS and use those instead of the below
|
|
||||||
for /f "delims=. tokens=1-3" %%v in ("%JAVA_VERSION%") do (
|
|
||||||
set MAJOR=%%v
|
|
||||||
set MINOR=%%w
|
|
||||||
set BUILD=%%x
|
|
||||||
|
|
||||||
set META_SIZE=-XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=256M
|
|
||||||
if "!MINOR!" LSS "8" (
|
|
||||||
set META_SIZE=-XX:PermSize=64M -XX:MaxPermSize=256M
|
|
||||||
)
|
|
||||||
|
|
||||||
set MEM_OPTS=!META_SIZE!
|
|
||||||
)
|
|
||||||
|
|
||||||
rem We use the value of the JAVA_OPTS environment variable if defined, rather than the config.
|
|
||||||
set _JAVA_OPTS=%JAVA_OPTS%
|
|
||||||
if "%_JAVA_OPTS%"=="" set _JAVA_OPTS=%CFG_OPTS%
|
|
||||||
|
|
||||||
set DEBUG_OPTS=
|
|
||||||
|
|
||||||
rem Loop through the arguments, building remaining args in args variable
|
|
||||||
set args=
|
|
||||||
:argsloop
|
|
||||||
if not "%~1"=="" (
|
|
||||||
rem Checks if the argument contains "-D" and if true, adds argument 1 with 2 and puts an equal sign between them.
|
|
||||||
rem This is done since batch considers "=" to be a delimiter so we need to circumvent this behavior with a small hack.
|
|
||||||
set arg1=%~1
|
|
||||||
if "!arg1:~0,2!"=="-D" (
|
|
||||||
set "args=%args% "%~1"="%~2""
|
|
||||||
shift
|
|
||||||
shift
|
|
||||||
goto argsloop
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%~1"=="-jvm-debug" (
|
|
||||||
if not "%~2"=="" (
|
|
||||||
rem This piece of magic somehow checks that an argument is a number
|
|
||||||
for /F "delims=0123456789" %%i in ("%~2") do (
|
|
||||||
set var="%%i"
|
|
||||||
)
|
|
||||||
if defined var (
|
|
||||||
rem Not a number, assume no argument given and default to 9999
|
|
||||||
set JPDA_PORT=9999
|
|
||||||
) else (
|
|
||||||
rem Port was given, shift arguments
|
|
||||||
set JPDA_PORT=%~2
|
|
||||||
shift
|
|
||||||
)
|
|
||||||
) else (
|
|
||||||
set JPDA_PORT=9999
|
|
||||||
)
|
|
||||||
shift
|
|
||||||
|
|
||||||
set DEBUG_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=!JPDA_PORT!
|
|
||||||
goto argsloop
|
|
||||||
)
|
|
||||||
rem else
|
|
||||||
set "args=%args% "%~1""
|
|
||||||
shift
|
|
||||||
goto argsloop
|
|
||||||
)
|
|
||||||
|
|
||||||
:run
|
|
||||||
|
|
||||||
if "!args!"=="" (
|
|
||||||
if defined DOUBLECLICKED (
|
|
||||||
set CMDS="ui"
|
|
||||||
) else set CMDS=!args!
|
|
||||||
) else set CMDS=!args!
|
|
||||||
|
|
||||||
rem We add a / in front, so we get file:///C: instead of file://C:
|
|
||||||
rem Java considers the later a UNC path.
|
|
||||||
rem We also attempt a solid effort at making it URI friendly.
|
|
||||||
rem We don't even bother with UNC paths.
|
|
||||||
set JAVA_FRIENDLY_HOME_1=/!ACTIVATOR_HOME:\=/!
|
|
||||||
set JAVA_FRIENDLY_HOME=/!JAVA_FRIENDLY_HOME_1: =%%20!
|
|
||||||
|
|
||||||
rem Checks if the command contains spaces to know if it should be wrapped in quotes or not
|
|
||||||
set NON_SPACED_CMD=%_JAVACMD: =%
|
|
||||||
if "%_JAVACMD%"=="%NON_SPACED_CMD%" %_JAVACMD% %DEBUG_OPTS% %MEM_OPTS% %ACTIVATOR_OPTS% %SBT_OPTS% %_JAVA_OPTS% "-Dactivator.home=%JAVA_FRIENDLY_HOME%" -jar "%ACTIVATOR_HOME%\libexec\%ACTIVATOR_LAUNCH_JAR%" %CMDS%
|
|
||||||
if NOT "%_JAVACMD%"=="%NON_SPACED_CMD%" "%_JAVACMD%" %DEBUG_OPTS% %MEM_OPTS% %ACTIVATOR_OPTS% %SBT_OPTS% %_JAVA_OPTS% "-Dactivator.home=%JAVA_FRIENDLY_HOME%" -jar "%ACTIVATOR_HOME%\libexec\%ACTIVATOR_LAUNCH_JAR%" %CMDS%
|
|
||||||
|
|
||||||
if ERRORLEVEL 1 goto error
|
|
||||||
goto end
|
|
||||||
|
|
||||||
:error
|
|
||||||
set ERROR_CODE=1
|
|
||||||
|
|
||||||
:end
|
|
||||||
|
|
||||||
@endlocal
|
|
||||||
|
|
||||||
exit /B %ERROR_CODE%
|
|
|
@ -1,13 +1,10 @@
|
||||||
name := """webapp"""
|
name := """play-routing"""
|
||||||
|
organization := "com.baeldung"
|
||||||
|
|
||||||
version := "1.0-SNAPSHOT"
|
version := "1.0-SNAPSHOT"
|
||||||
|
|
||||||
lazy val root = (project in file(".")).enablePlugins(PlayJava)
|
lazy val root = (project in file(".")).enablePlugins(PlayJava)
|
||||||
|
|
||||||
scalaVersion := "2.11.7"
|
scalaVersion := "2.13.0"
|
||||||
|
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies += guice
|
||||||
javaJdbc,
|
|
||||||
cache,
|
|
||||||
javaWs
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,353 +1,2 @@
|
||||||
# This is the main configuration file for the application.
|
# This is the main configuration file for the application.
|
||||||
# https://www.playframework.com/documentation/latest/ConfigFile
|
# https://www.playframework.com/documentation/latest/ConfigFile
|
||||||
# ~~~~~
|
|
||||||
# Play uses HOCON as its configuration file format. HOCON has a number
|
|
||||||
# of advantages over other config formats, but there are two things that
|
|
||||||
# can be used when modifying settings.
|
|
||||||
#
|
|
||||||
# You can include other configuration files in this main application.conf file:
|
|
||||||
#include "extra-config.conf"
|
|
||||||
#
|
|
||||||
# You can declare variables and substitute for them:
|
|
||||||
#mykey = ${some.value}
|
|
||||||
#
|
|
||||||
# And if an environment variable exists when there is no other subsitution, then
|
|
||||||
# HOCON will fall back to substituting environment variable:
|
|
||||||
#mykey = ${JAVA_HOME}
|
|
||||||
|
|
||||||
## Akka
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaAkka#Configuration
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaAkka#Configuration
|
|
||||||
# ~~~~~
|
|
||||||
# Play uses Akka internally and exposes Akka Streams and actors in Websockets and
|
|
||||||
# other streaming HTTP responses.
|
|
||||||
akka {
|
|
||||||
# "akka.log-config-on-start" is extraordinarly useful because it log the complete
|
|
||||||
# configuration at INFO level, including defaults and overrides, so it s worth
|
|
||||||
# putting at the very top.
|
|
||||||
#
|
|
||||||
# Put the following in your conf/logback.xml file:
|
|
||||||
#
|
|
||||||
# <logger name="akka.actor" level="INFO" />
|
|
||||||
#
|
|
||||||
# And then uncomment this line to debug the configuration.
|
|
||||||
#
|
|
||||||
#log-config-on-start = true
|
|
||||||
}
|
|
||||||
|
|
||||||
## Secret key
|
|
||||||
# http://www.playframework.com/documentation/latest/ApplicationSecret
|
|
||||||
# ~~~~~
|
|
||||||
# The secret key is used to sign Play's session cookie.
|
|
||||||
# This must be changed for production, but we don't recommend you change it in this file.
|
|
||||||
play.crypto.secret = "changeme"
|
|
||||||
|
|
||||||
## Modules
|
|
||||||
# https://www.playframework.com/documentation/latest/Modules
|
|
||||||
# ~~~~~
|
|
||||||
# Control which modules are loaded when Play starts. Note that modules are
|
|
||||||
# the replacement for "GlobalSettings", which are deprecated in 2.5.x.
|
|
||||||
# Please see https://www.playframework.com/documentation/latest/GlobalSettings
|
|
||||||
# for more information.
|
|
||||||
#
|
|
||||||
# You can also extend Play functionality by using one of the publically available
|
|
||||||
# Play modules: https://playframework.com/documentation/latest/ModuleDirectory
|
|
||||||
play.modules {
|
|
||||||
# By default, Play will load any class called Module that is defined
|
|
||||||
# in the root package (the "app" directory), or you can define them
|
|
||||||
# explicitly below.
|
|
||||||
# If there are any built-in modules that you want to disable, you can list them here.
|
|
||||||
#enabled += my.application.Module
|
|
||||||
|
|
||||||
# If there are any built-in modules that you want to disable, you can list them here.
|
|
||||||
#disabled += ""
|
|
||||||
}
|
|
||||||
|
|
||||||
## IDE
|
|
||||||
# https://www.playframework.com/documentation/latest/IDE
|
|
||||||
# ~~~~~
|
|
||||||
# Depending on your IDE, you can add a hyperlink for errors that will jump you
|
|
||||||
# directly to the code location in the IDE in dev mode. The following line makes
|
|
||||||
# use of the IntelliJ IDEA REST interface:
|
|
||||||
#play.editor="http://localhost:63342/api/file/?file=%s&line=%s"
|
|
||||||
|
|
||||||
## Internationalisation
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaI18N
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaI18N
|
|
||||||
# ~~~~~
|
|
||||||
# Play comes with its own i18n settings, which allow the user's preferred language
|
|
||||||
# to map through to internal messages, or allow the language to be stored in a cookie.
|
|
||||||
play.i18n {
|
|
||||||
# The application languages
|
|
||||||
langs = [ "en" ]
|
|
||||||
|
|
||||||
# Whether the language cookie should be secure or not
|
|
||||||
#langCookieSecure = true
|
|
||||||
|
|
||||||
# Whether the HTTP only attribute of the cookie should be set to true
|
|
||||||
#langCookieHttpOnly = true
|
|
||||||
}
|
|
||||||
|
|
||||||
## Play HTTP settings
|
|
||||||
# ~~~~~
|
|
||||||
play.http {
|
|
||||||
## Router
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaRouting
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaRouting
|
|
||||||
# ~~~~~
|
|
||||||
# Define the Router object to use for this application.
|
|
||||||
# This router will be looked up first when the application is starting up,
|
|
||||||
# so make sure this is the entry point.
|
|
||||||
# Furthermore, it's assumed your route file is named properly.
|
|
||||||
# So for an application router like `my.application.Router`,
|
|
||||||
# you may need to define a router file `conf/my.application.routes`.
|
|
||||||
# Default to Routes in the root package (aka "apps" folder) (and conf/routes)
|
|
||||||
#router = my.application.Router
|
|
||||||
|
|
||||||
## Action Creator
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaActionCreator
|
|
||||||
# ~~~~~
|
|
||||||
#actionCreator = null
|
|
||||||
|
|
||||||
## ErrorHandler
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaRouting
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaRouting
|
|
||||||
# ~~~~~
|
|
||||||
# If null, will attempt to load a class called ErrorHandler in the root package,
|
|
||||||
#errorHandler = null
|
|
||||||
|
|
||||||
## Filters
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaHttpFilters
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaHttpFilters
|
|
||||||
# ~~~~~
|
|
||||||
# Filters run code on every request. They can be used to perform
|
|
||||||
# common logic for all your actions, e.g. adding common headers.
|
|
||||||
# Defaults to "Filters" in the root package (aka "apps" folder)
|
|
||||||
# Alternatively you can explicitly register a class here.
|
|
||||||
#filters = my.application.Filters
|
|
||||||
|
|
||||||
## Session & Flash
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaSessionFlash
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaSessionFlash
|
|
||||||
# ~~~~~
|
|
||||||
session {
|
|
||||||
# Sets the cookie to be sent only over HTTPS.
|
|
||||||
#secure = true
|
|
||||||
|
|
||||||
# Sets the cookie to be accessed only by the server.
|
|
||||||
#httpOnly = true
|
|
||||||
|
|
||||||
# Sets the max-age field of the cookie to 5 minutes.
|
|
||||||
# NOTE: this only sets when the browser will discard the cookie. Play will consider any
|
|
||||||
# cookie value with a valid signature to be a valid session forever. To implement a server side session timeout,
|
|
||||||
# you need to put a timestamp in the session and check it at regular intervals to possibly expire it.
|
|
||||||
#maxAge = 300
|
|
||||||
|
|
||||||
# Sets the domain on the session cookie.
|
|
||||||
#domain = "example.com"
|
|
||||||
}
|
|
||||||
|
|
||||||
flash {
|
|
||||||
# Sets the cookie to be sent only over HTTPS.
|
|
||||||
#secure = true
|
|
||||||
|
|
||||||
# Sets the cookie to be accessed only by the server.
|
|
||||||
#httpOnly = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
## Netty Provider
|
|
||||||
# https://www.playframework.com/documentation/latest/SettingsNetty
|
|
||||||
# ~~~~~
|
|
||||||
play.server.netty {
|
|
||||||
# Whether the Netty wire should be logged
|
|
||||||
#log.wire = true
|
|
||||||
|
|
||||||
# If you run Play on Linux, you can use Netty's native socket transport
|
|
||||||
# for higher performance with less garbage.
|
|
||||||
#transport = "native"
|
|
||||||
}
|
|
||||||
|
|
||||||
## WS (HTTP Client)
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaWS#Configuring-WS
|
|
||||||
# ~~~~~
|
|
||||||
# The HTTP client primarily used for REST APIs. The default client can be
|
|
||||||
# configured directly, but you can also create different client instances
|
|
||||||
# with customized settings. You must enable this by adding to build.sbt:
|
|
||||||
#
|
|
||||||
# libraryDependencies += ws // or javaWs if using java
|
|
||||||
#
|
|
||||||
play.ws {
|
|
||||||
# Sets HTTP requests not to follow 302 requests
|
|
||||||
#followRedirects = false
|
|
||||||
|
|
||||||
# Sets the maximum number of open HTTP connections for the client.
|
|
||||||
#ahc.maxConnectionsTotal = 50
|
|
||||||
|
|
||||||
## WS SSL
|
|
||||||
# https://www.playframework.com/documentation/latest/WsSSL
|
|
||||||
# ~~~~~
|
|
||||||
ssl {
|
|
||||||
# Configuring HTTPS with Play WS does not require programming. You can
|
|
||||||
# set up both trustManager and keyManager for mutual authentication, and
|
|
||||||
# turn on JSSE debugging in development with a reload.
|
|
||||||
#debug.handshake = true
|
|
||||||
#trustManager = {
|
|
||||||
# stores = [
|
|
||||||
# { type = "JKS", path = "exampletrust.jks" }
|
|
||||||
# ]
|
|
||||||
#}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
## Cache
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaCache
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaCache
|
|
||||||
# ~~~~~
|
|
||||||
# Play comes with an integrated cache API that can reduce the operational
|
|
||||||
# overhead of repeated requests. You must enable this by adding to build.sbt:
|
|
||||||
#
|
|
||||||
# libraryDependencies += cache
|
|
||||||
#
|
|
||||||
play.cache {
|
|
||||||
# If you want to bind several caches, you can bind the individually
|
|
||||||
#bindCaches = ["db-cache", "user-cache", "session-cache"]
|
|
||||||
}
|
|
||||||
|
|
||||||
## Filters
|
|
||||||
# https://www.playframework.com/documentation/latest/Filters
|
|
||||||
# ~~~~~
|
|
||||||
# There are a number of built-in filters that can be enabled and configured
|
|
||||||
# to give Play greater security. You must enable this by adding to build.sbt:
|
|
||||||
#
|
|
||||||
# libraryDependencies += filters
|
|
||||||
#
|
|
||||||
play.filters {
|
|
||||||
## CORS filter configuration
|
|
||||||
# https://www.playframework.com/documentation/latest/CorsFilter
|
|
||||||
# ~~~~~
|
|
||||||
# CORS is a protocol that allows web applications to make requests from the browser
|
|
||||||
# across different domains.
|
|
||||||
# NOTE: You MUST apply the CORS configuration before the CSRF filter, as CSRF has
|
|
||||||
# dependencies on CORS settings.
|
|
||||||
cors {
|
|
||||||
# Filter paths by a whitelist of path prefixes
|
|
||||||
#pathPrefixes = ["/some/path", ...]
|
|
||||||
|
|
||||||
# The allowed origins. If null, all origins are allowed.
|
|
||||||
#allowedOrigins = ["http://www.example.com"]
|
|
||||||
|
|
||||||
# The allowed HTTP methods. If null, all methods are allowed
|
|
||||||
#allowedHttpMethods = ["GET", "POST"]
|
|
||||||
}
|
|
||||||
|
|
||||||
## CSRF Filter
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaCsrf#Applying-a-global-CSRF-filter
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaCsrf#Applying-a-global-CSRF-filter
|
|
||||||
# ~~~~~
|
|
||||||
# Play supports multiple methods for verifying that a request is not a CSRF request.
|
|
||||||
# The primary mechanism is a CSRF token. This token gets placed either in the query string
|
|
||||||
# or body of every form submitted, and also gets placed in the users session.
|
|
||||||
# Play then verifies that both tokens are present and match.
|
|
||||||
csrf {
|
|
||||||
# Sets the cookie to be sent only over HTTPS
|
|
||||||
#cookie.secure = true
|
|
||||||
|
|
||||||
# Defaults to CSRFErrorHandler in the root package.
|
|
||||||
#errorHandler = MyCSRFErrorHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
## Security headers filter configuration
|
|
||||||
# https://www.playframework.com/documentation/latest/SecurityHeaders
|
|
||||||
# ~~~~~
|
|
||||||
# Defines security headers that prevent XSS attacks.
|
|
||||||
# If enabled, then all options are set to the below configuration by default:
|
|
||||||
headers {
|
|
||||||
# The X-Frame-Options header. If null, the header is not set.
|
|
||||||
#frameOptions = "DENY"
|
|
||||||
|
|
||||||
# The X-XSS-Protection header. If null, the header is not set.
|
|
||||||
#xssProtection = "1; mode=block"
|
|
||||||
|
|
||||||
# The X-Content-Type-Options header. If null, the header is not set.
|
|
||||||
#contentTypeOptions = "nosniff"
|
|
||||||
|
|
||||||
# The X-Permitted-Cross-Domain-Policies header. If null, the header is not set.
|
|
||||||
#permittedCrossDomainPolicies = "master-only"
|
|
||||||
|
|
||||||
# The Content-Security-Policy header. If null, the header is not set.
|
|
||||||
#contentSecurityPolicy = "default-src 'self'"
|
|
||||||
}
|
|
||||||
|
|
||||||
## Allowed hosts filter configuration
|
|
||||||
# https://www.playframework.com/documentation/latest/AllowedHostsFilter
|
|
||||||
# ~~~~~
|
|
||||||
# Play provides a filter that lets you configure which hosts can access your application.
|
|
||||||
# This is useful to prevent cache poisoning attacks.
|
|
||||||
hosts {
|
|
||||||
# Allow requests to example.com, its subdomains, and localhost:9000.
|
|
||||||
#allowed = [".example.com", "localhost:9000"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
## Evolutions
|
|
||||||
# https://www.playframework.com/documentation/latest/Evolutions
|
|
||||||
# ~~~~~
|
|
||||||
# Evolutions allows database scripts to be automatically run on startup in dev mode
|
|
||||||
# for database migrations. You must enable this by adding to build.sbt:
|
|
||||||
#
|
|
||||||
# libraryDependencies += evolutions
|
|
||||||
#
|
|
||||||
play.evolutions {
|
|
||||||
# You can disable evolutions for a specific datasource if necessary
|
|
||||||
#db.default.enabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
## Database Connection Pool
|
|
||||||
# https://www.playframework.com/documentation/latest/SettingsJDBC
|
|
||||||
# ~~~~~
|
|
||||||
# Play doesn't require a JDBC database to run, but you can easily enable one.
|
|
||||||
#
|
|
||||||
# libraryDependencies += jdbc
|
|
||||||
#
|
|
||||||
play.db {
|
|
||||||
# The combination of these two settings results in "db.default" as the
|
|
||||||
# default JDBC pool:
|
|
||||||
#config = "db"
|
|
||||||
#default = "default"
|
|
||||||
|
|
||||||
# Play uses HikariCP as the default connection pool. You can override
|
|
||||||
# settings by changing the prototype:
|
|
||||||
prototype {
|
|
||||||
# Sets a fixed JDBC connection pool size of 50
|
|
||||||
#hikaricp.minimumIdle = 50
|
|
||||||
#hikaricp.maximumPoolSize = 50
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
## JDBC Datasource
|
|
||||||
# https://www.playframework.com/documentation/latest/JavaDatabase
|
|
||||||
# https://www.playframework.com/documentation/latest/ScalaDatabase
|
|
||||||
# ~~~~~
|
|
||||||
# Once JDBC datasource is set up, you can work with several different
|
|
||||||
# database options:
|
|
||||||
#
|
|
||||||
# Slick (Scala preferred option): https://www.playframework.com/documentation/latest/PlaySlick
|
|
||||||
# JPA (Java preferred option): https://playframework.com/documentation/latest/JavaJPA
|
|
||||||
# EBean: https://playframework.com/documentation/latest/JavaEbean
|
|
||||||
# Anorm: https://www.playframework.com/documentation/latest/ScalaAnorm
|
|
||||||
#
|
|
||||||
db {
|
|
||||||
# You can declare as many datasources as you want.
|
|
||||||
# By convention, the default datasource is named `default`
|
|
||||||
|
|
||||||
# https://www.playframework.com/documentation/latest/Developing-with-the-H2-Database
|
|
||||||
#default.driver = org.h2.Driver
|
|
||||||
#default.url = "jdbc:h2:mem:play"
|
|
||||||
#default.username = sa
|
|
||||||
#default.password = ""
|
|
||||||
|
|
||||||
# You can turn on SQL logging for any datasource
|
|
||||||
# https://www.playframework.com/documentation/latest/Highlights25#Logging-SQL-statements
|
|
||||||
#default.logSql=true
|
|
||||||
}
|
|
||||||
|
|
|
@ -27,12 +27,6 @@
|
||||||
<logger name="play" level="INFO" />
|
<logger name="play" level="INFO" />
|
||||||
<logger name="application" level="DEBUG" />
|
<logger name="application" level="DEBUG" />
|
||||||
|
|
||||||
<!-- Off these ones as they are annoying, and anyway we manage configuration ourselves -->
|
|
||||||
<logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF" />
|
|
||||||
<logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF" />
|
|
||||||
<logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF" />
|
|
||||||
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />
|
|
||||||
|
|
||||||
<root level="WARN">
|
<root level="WARN">
|
||||||
<appender-ref ref="ASYNCFILE" />
|
<appender-ref ref="ASYNCFILE" />
|
||||||
<appender-ref ref="ASYNCSTDOUT" />
|
<appender-ref ref="ASYNCSTDOUT" />
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
GET / controllers.HomeController.index(author="Baeldung",id:Int?=1)
|
# Routes
|
||||||
GET /:author controllers.HomeController.index(author,id:Int?=1)
|
# This file defines all application routes (Higher priority routes first)
|
||||||
GET /greet/:name/:age controllers.HomeController.greet(name,age:Integer)
|
# ~~~~
|
||||||
GET /square/$num<[0-9]+> controllers.HomeController.squareMe(num:Long)
|
|
||||||
|
# An example controller showing a sample home page
|
||||||
|
GET / controllers.HomeController.index
|
||||||
|
GET /writer controllers.HomeController.writer(author = "Baeldung", id: Int ?= 1)
|
||||||
|
GET /writer/:author controllers.HomeController.writer(author: String, id: Int ?= 1)
|
||||||
|
GET /baeldung/:id controllers.HomeController.viewUser(id: String)
|
||||||
|
GET /greet/:name/:age controllers.HomeController.greet(name: String, age: Integer)
|
||||||
|
GET /square/$num<[0-9]+> controllers.HomeController.squareMe(num: Long)
|
||||||
|
GET /*data controllers.HomeController.introduceMe(data)
|
||||||
|
|
||||||
# Map static resources from the /public folder to the /assets URL path
|
# Map static resources from the /public folder to the /assets URL path
|
||||||
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
|
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
|
||||||
GET /*data controllers.HomeController.introduceMe(data)
|
|
||||||
|
|
Binary file not shown.
|
@ -1,4 +1 @@
|
||||||
#Activator-generated Properties
|
sbt.version=1.2.8
|
||||||
#Fri Sep 30 14:25:10 EAT 2016
|
|
||||||
template.uuid=26c759a5-daf0-4e02-bcfa-ac69725267c0
|
|
||||||
sbt.version=0.13.11
|
|
||||||
|
|
|
@ -1,21 +1,7 @@
|
||||||
// The Play plugin
|
// The Play plugin
|
||||||
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.8")
|
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.3")
|
||||||
|
|
||||||
// Web plugins
|
// Defines scaffolding (found under .g8 folder)
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-coffeescript" % "1.0.0")
|
// http://www.foundweekends.org/giter8/scaffolding.html
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.1.0")
|
// sbt "g8Scaffold form"
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-jshint" % "1.0.4")
|
addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0")
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-rjs" % "1.0.8")
|
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.1.1")
|
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-mocha" % "1.1.0")
|
|
||||||
addSbtPlugin("org.irundaia.sbt" % "sbt-sassify" % "1.4.6")
|
|
||||||
|
|
||||||
// Play enhancer - this automatically generates getters/setters for public fields
|
|
||||||
// and rewrites accessors of these fields to use the getters/setters. Remove this
|
|
||||||
// plugin if you prefer not to have this feature, or disable on a per project
|
|
||||||
// basis using disablePlugins(PlayEnhancer) in your build.sbt
|
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-play-enhancer" % "1.1.0")
|
|
||||||
|
|
||||||
// Play Ebean support, to enable, uncomment this line, and enable in your build.sbt using
|
|
||||||
// enablePlugins(PlayEbean).
|
|
||||||
// addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "3.0.2")
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
if (window.console) {
|
|
||||||
console.log("Welcome to your Play application's JavaScript!");
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import org.junit.*;
|
|
||||||
|
|
||||||
import play.mvc.*;
|
|
||||||
import play.test.*;
|
|
||||||
import play.data.DynamicForm;
|
|
||||||
import play.data.validation.ValidationError;
|
|
||||||
import play.data.validation.Constraints.RequiredValidator;
|
|
||||||
import play.i18n.Lang;
|
|
||||||
import play.libs.F;
|
|
||||||
import play.libs.F.*;
|
|
||||||
import play.twirl.api.Content;
|
|
||||||
|
|
||||||
import static play.test.Helpers.*;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Simple (JUnit) tests that can call all parts of a play app.
|
|
||||||
* If you are interested in mocking a whole application, see the wiki for more details.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ApplicationUnitTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void simpleCheck() {
|
|
||||||
int a = 1 + 1;
|
|
||||||
assertEquals(2, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void renderTemplate() {
|
|
||||||
Content html = views.html.index.render("Your new application is ready.");
|
|
||||||
assertEquals("text/html", html.contentType());
|
|
||||||
assertTrue(html.body().contains("Your new application is ready."));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
import org.junit.*;
|
|
||||||
|
|
||||||
import play.mvc.*;
|
|
||||||
import play.test.*;
|
|
||||||
|
|
||||||
import static play.test.Helpers.*;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import static org.fluentlenium.core.filter.FilterConstructor.*;
|
|
||||||
|
|
||||||
public class IntegrationTest {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* add your integration test here
|
|
||||||
* in this example we just check if the welcome page is being shown
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void test() {
|
|
||||||
running(testServer(3333, fakeApplication(inMemoryDatabase())), HTMLUNIT, browser -> {
|
|
||||||
browser.goTo("http://localhost:3333");
|
|
||||||
assertTrue(browser.pageSource().contains("Your new application is ready."));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package controllers;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import play.Application;
|
||||||
|
import play.inject.guice.GuiceApplicationBuilder;
|
||||||
|
import play.mvc.Http;
|
||||||
|
import play.mvc.Result;
|
||||||
|
import play.test.WithApplication;
|
||||||
|
import play.twirl.api.Html;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.CompletionStage;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static play.mvc.Http.Status.*;
|
||||||
|
import static play.test.Helpers.GET;
|
||||||
|
import static play.test.Helpers.route;
|
||||||
|
|
||||||
|
public class HomeControllerUnitTest extends WithApplication {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Application provideApplication() {
|
||||||
|
return new GuiceApplicationBuilder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenRequest_whenRootPath_ThenStatusOkay() {
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(GET)
|
||||||
|
.uri("/");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
assertEquals(OK, result.status());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
logs
|
logs
|
||||||
target
|
target
|
||||||
/.idea
|
/.idea
|
||||||
|
/.g8
|
||||||
/.idea_modules
|
/.idea_modules
|
||||||
/.classpath
|
/.classpath
|
||||||
/.project
|
/.project
|
|
@ -0,0 +1,91 @@
|
||||||
|
package controllers;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import model.Student;
|
||||||
|
import play.libs.Json;
|
||||||
|
import play.libs.concurrent.HttpExecutionContext;
|
||||||
|
import play.mvc.Controller;
|
||||||
|
import play.mvc.Http;
|
||||||
|
import play.mvc.Result;
|
||||||
|
import store.StudentStore;
|
||||||
|
import utils.Util;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CompletionStage;
|
||||||
|
|
||||||
|
import static java.util.concurrent.CompletableFuture.supplyAsync;
|
||||||
|
|
||||||
|
public class StudentController extends Controller {
|
||||||
|
private HttpExecutionContext ec;
|
||||||
|
private StudentStore studentStore;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public StudentController(HttpExecutionContext ec, StudentStore studentStore) {
|
||||||
|
this.studentStore = studentStore;
|
||||||
|
this.ec = ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletionStage<Result> create(Http.Request request) {
|
||||||
|
JsonNode json = request.body().asJson();
|
||||||
|
return supplyAsync(() -> {
|
||||||
|
if (json == null) {
|
||||||
|
return badRequest(Util.createResponse("Expecting Json data", false));
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Student> studentOptional = studentStore.addStudent(Json.fromJson(json, Student.class));
|
||||||
|
return studentOptional.map(student -> {
|
||||||
|
JsonNode jsonObject = Json.toJson(student);
|
||||||
|
return created(Util.createResponse(jsonObject, true));
|
||||||
|
}).orElse(internalServerError(Util.createResponse("Could not create data.", false)));
|
||||||
|
}, ec.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletionStage<Result> listStudents() {
|
||||||
|
return supplyAsync(() -> {
|
||||||
|
Set<Student> result = studentStore.getAllStudents();
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode jsonData = mapper.convertValue(result, JsonNode.class);
|
||||||
|
return ok(Util.createResponse(jsonData, true));
|
||||||
|
}, ec.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletionStage<Result> retrieve(int id) {
|
||||||
|
return supplyAsync(() -> {
|
||||||
|
final Optional<Student> studentOptional = studentStore.getStudent(id);
|
||||||
|
return studentOptional.map(student -> {
|
||||||
|
JsonNode jsonObjects = Json.toJson(student);
|
||||||
|
return ok(Util.createResponse(jsonObjects, true));
|
||||||
|
}).orElse(notFound(Util.createResponse("Student with id:" + id + " not found", false)));
|
||||||
|
}, ec.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletionStage<Result> update(Http.Request request) {
|
||||||
|
JsonNode json = request.body().asJson();
|
||||||
|
return supplyAsync(() -> {
|
||||||
|
if (json == null) {
|
||||||
|
return badRequest(Util.createResponse("Expecting Json data", false));
|
||||||
|
}
|
||||||
|
Optional<Student> studentOptional = studentStore.updateStudent(Json.fromJson(json, Student.class));
|
||||||
|
return studentOptional.map(student -> {
|
||||||
|
if (student == null) {
|
||||||
|
return notFound(Util.createResponse("Student not found", false));
|
||||||
|
}
|
||||||
|
JsonNode jsonObject = Json.toJson(student);
|
||||||
|
return ok(Util.createResponse(jsonObject, true));
|
||||||
|
}).orElse(internalServerError(Util.createResponse("Could not create data.", false)));
|
||||||
|
}, ec.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletionStage<Result> delete(int id) {
|
||||||
|
return supplyAsync(() -> {
|
||||||
|
boolean status = studentStore.deleteStudent(id);
|
||||||
|
if (!status) {
|
||||||
|
return notFound(Util.createResponse("Student with id:" + id + " not found", false));
|
||||||
|
}
|
||||||
|
return ok(Util.createResponse("Student with id:" + id + " deleted", true));
|
||||||
|
}, ec.current());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,19 @@
|
||||||
package models;
|
package model;
|
||||||
|
|
||||||
public class Student {
|
public class Student {
|
||||||
private String firstName;
|
private String firstName;
|
||||||
private String lastName;
|
private String lastName;
|
||||||
private int age;
|
private int age;
|
||||||
private int id;
|
private int id;
|
||||||
public Student(){}
|
|
||||||
public Student(String firstName, String lastName, int age) {
|
public Student() {
|
||||||
super();
|
}
|
||||||
|
|
||||||
|
public Student(String firstName, String lastName, int age, int id) {
|
||||||
this.firstName = firstName;
|
this.firstName = firstName;
|
||||||
this.lastName = lastName;
|
this.lastName = lastName;
|
||||||
this.age = age;
|
this.age = age;
|
||||||
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFirstName() {
|
public String getFirstName() {
|
||||||
|
@ -43,5 +47,4 @@ public class Student {
|
||||||
public void setId(int id) {
|
public void setId(int id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package store;
|
||||||
|
|
||||||
|
import model.Student;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class StudentStore {
|
||||||
|
private Map<Integer, Student> students = new HashMap<>();
|
||||||
|
|
||||||
|
public Optional<Student> addStudent(Student student) {
|
||||||
|
int id = students.size();
|
||||||
|
student.setId(id);
|
||||||
|
students.put(id, student);
|
||||||
|
return Optional.ofNullable(student);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Student> getStudent(int id) {
|
||||||
|
return Optional.ofNullable(students.get(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Student> getAllStudents() {
|
||||||
|
return new HashSet<>(students.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Student> updateStudent(Student student) {
|
||||||
|
int id = student.getId();
|
||||||
|
if (students.containsKey(id)) {
|
||||||
|
students.put(id, student);
|
||||||
|
return Optional.ofNullable(student);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteStudent(int id) {
|
||||||
|
return students.remove(id) != null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,17 @@
|
||||||
package util;
|
package utils;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import play.libs.Json;
|
import play.libs.Json;
|
||||||
|
|
||||||
public class Util {
|
public class Util {
|
||||||
public static ObjectNode createResponse(Object response, boolean ok) {
|
public static ObjectNode createResponse(Object response, boolean ok) {
|
||||||
ObjectNode result = Json.newObject();
|
ObjectNode result = Json.newObject();
|
||||||
result.put("isSuccessfull", ok);
|
result.put("isSuccessful", ok);
|
||||||
if (response instanceof String)
|
if (response instanceof String) {
|
||||||
result.put("body", (String) response);
|
result.put("body", (String) response);
|
||||||
else result.put("body", (JsonNode) response);
|
} else {
|
||||||
|
result.putPOJO("body", response);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
name := """student-api"""
|
||||||
|
organization := "com.baeldung"
|
||||||
|
|
||||||
|
version := "1.0-SNAPSHOT"
|
||||||
|
|
||||||
|
lazy val root = (project in file(".")).enablePlugins(PlayJava)
|
||||||
|
|
||||||
|
scalaVersion := "2.13.0"
|
||||||
|
|
||||||
|
libraryDependencies += guice
|
|
@ -0,0 +1,2 @@
|
||||||
|
# This is the main configuration file for the application.
|
||||||
|
# https://www.playframework.com/documentation/latest/ConfigFile
|
|
@ -0,0 +1,35 @@
|
||||||
|
<!-- https://www.playframework.com/documentation/latest/SettingsLogger -->
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />
|
||||||
|
|
||||||
|
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||||
|
<file>${application.home:-.}/logs/application.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="play" level="INFO" />
|
||||||
|
<logger name="application" level="DEBUG" />
|
||||||
|
|
||||||
|
<root level="WARN">
|
||||||
|
<appender-ref ref="ASYNCFILE" />
|
||||||
|
<appender-ref ref="ASYNCSTDOUT" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</configuration>
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Routes
|
||||||
|
# This file defines all application routes (Higher priority routes first)
|
||||||
|
# ~~~~
|
||||||
|
|
||||||
|
GET / controllers.StudentController.listStudents()
|
||||||
|
GET /:id controllers.StudentController.retrieve(id:Int)
|
||||||
|
POST / controllers.StudentController.create(request: Request)
|
||||||
|
PUT / controllers.StudentController.update(request: Request)
|
||||||
|
DELETE /:id controllers.StudentController.delete(id:Int)
|
||||||
|
|
||||||
|
# Map static resources from the /public folder to the /assets URL path
|
||||||
|
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
|
|
@ -0,0 +1 @@
|
||||||
|
sbt.version=1.2.8
|
|
@ -0,0 +1,7 @@
|
||||||
|
// The Play plugin
|
||||||
|
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.3")
|
||||||
|
|
||||||
|
// Defines scaffolding (found under .g8 folder)
|
||||||
|
// http://www.foundweekends.org/giter8/scaffolding.html
|
||||||
|
// sbt "g8Scaffold form"
|
||||||
|
addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0")
|
|
@ -1,172 +0,0 @@
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import model.Student;
|
|
||||||
import play.test.*;
|
|
||||||
import static play.test.Helpers.*;
|
|
||||||
|
|
||||||
public class ApplicationLiveTest{
|
|
||||||
private static final String BASE_URL = "http://localhost:9000";
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInServer() throws Exception {
|
|
||||||
TestServer server = testServer(3333);
|
|
||||||
running(server, () -> {
|
|
||||||
try {
|
|
||||||
WSClient ws = play.libs.ws.WS.newClient(3333);
|
|
||||||
CompletionStage<WSResponse> completionStage = ws.url("/").get();
|
|
||||||
WSResponse response = completionStage.toCompletableFuture().get();
|
|
||||||
ws.close();
|
|
||||||
assertEquals(OK, response.getStatus());
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@Test
|
|
||||||
public void whenCreatesRecord_thenCorrect() {
|
|
||||||
Student student = new Student("jody", "west", 50);
|
|
||||||
JSONObject obj = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student)));
|
|
||||||
assertTrue(obj.getBoolean("isSuccessfull"));
|
|
||||||
JSONObject body = obj.getJSONObject("body");
|
|
||||||
assertEquals(student.getAge(), body.getInt("age"));
|
|
||||||
assertEquals(student.getFirstName(), body.getString("firstName"));
|
|
||||||
assertEquals(student.getLastName(), body.getString("lastName"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void whenDeletesCreatedRecord_thenCorrect() {
|
|
||||||
Student student = new Student("Usain", "Bolt", 25);
|
|
||||||
JSONObject ob1 = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student))).getJSONObject("body");
|
|
||||||
int id = ob1.getInt("id");
|
|
||||||
JSONObject obj1 = new JSONObject(makeRequest(BASE_URL + "/" + id, "POST", new JSONObject()));
|
|
||||||
assertTrue(obj1.getBoolean("isSuccessfull"));
|
|
||||||
makeRequest(BASE_URL + "/" + id, "DELETE", null);
|
|
||||||
JSONObject obj2 = new JSONObject(makeRequest(BASE_URL + "/" + id, "POST", new JSONObject()));
|
|
||||||
assertFalse(obj2.getBoolean("isSuccessfull"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void whenUpdatesCreatedRecord_thenCorrect() {
|
|
||||||
Student student = new Student("john", "doe", 50);
|
|
||||||
JSONObject body1 = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student))).getJSONObject("body");
|
|
||||||
assertEquals(student.getAge(), body1.getInt("age"));
|
|
||||||
int newAge = 60;
|
|
||||||
body1.put("age", newAge);
|
|
||||||
JSONObject body2 = new JSONObject(makeRequest(BASE_URL, "PUT", body1)).getJSONObject("body");
|
|
||||||
assertFalse(student.getAge() == body2.getInt("age"));
|
|
||||||
assertTrue(newAge == body2.getInt("age"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void whenGetsAllRecords_thenCorrect() {
|
|
||||||
Student student1 = new Student("jane", "daisy", 50);
|
|
||||||
Student student2 = new Student("john", "daniel", 60);
|
|
||||||
Student student3 = new Student("don", "mason", 55);
|
|
||||||
Student student4 = new Student("scarlet", "ohara", 90);
|
|
||||||
|
|
||||||
makeRequest(BASE_URL, "POST", new JSONObject(student1));
|
|
||||||
makeRequest(BASE_URL, "POST", new JSONObject(student2));
|
|
||||||
makeRequest(BASE_URL, "POST", new JSONObject(student3));
|
|
||||||
makeRequest(BASE_URL, "POST", new JSONObject(student4));
|
|
||||||
|
|
||||||
JSONObject objects = new JSONObject(makeRequest(BASE_URL, "GET", null));
|
|
||||||
assertTrue(objects.getBoolean("isSuccessfull"));
|
|
||||||
JSONArray array = objects.getJSONArray("body");
|
|
||||||
assertTrue(array.length() >= 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String makeRequest(String myUrl, String httpMethod, JSONObject parameters) {
|
|
||||||
|
|
||||||
URL url = null;
|
|
||||||
try {
|
|
||||||
url = new URL(myUrl);
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
HttpURLConnection conn = null;
|
|
||||||
try {
|
|
||||||
|
|
||||||
conn = (HttpURLConnection) url.openConnection();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
conn.setDoInput(true);
|
|
||||||
|
|
||||||
conn.setReadTimeout(10000);
|
|
||||||
|
|
||||||
conn.setRequestProperty("Content-Type", "application/json");
|
|
||||||
DataOutputStream dos = null;
|
|
||||||
int respCode = 0;
|
|
||||||
String inputString = null;
|
|
||||||
try {
|
|
||||||
conn.setRequestMethod(httpMethod);
|
|
||||||
|
|
||||||
if (Arrays.asList("POST", "PUT").contains(httpMethod)) {
|
|
||||||
String params = parameters.toString();
|
|
||||||
|
|
||||||
conn.setDoOutput(true);
|
|
||||||
|
|
||||||
dos = new DataOutputStream(conn.getOutputStream());
|
|
||||||
dos.writeBytes(params);
|
|
||||||
dos.flush();
|
|
||||||
dos.close();
|
|
||||||
}
|
|
||||||
respCode = conn.getResponseCode();
|
|
||||||
if (respCode != 200 && respCode != 201) {
|
|
||||||
String error = inputStreamToString(conn.getErrorStream());
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
inputString = inputStreamToString(conn.getInputStream());
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return inputString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String inputStreamToString(InputStream is) {
|
|
||||||
BufferedReader br = null;
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
String line;
|
|
||||||
try {
|
|
||||||
|
|
||||||
br = new BufferedReader(new InputStreamReader(is));
|
|
||||||
while ((line = br.readLine()) != null) {
|
|
||||||
sb.append(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
if (br != null) {
|
|
||||||
try {
|
|
||||||
br.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
package controllers;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import org.junit.Test;
|
||||||
|
import play.Application;
|
||||||
|
import play.inject.guice.GuiceApplicationBuilder;
|
||||||
|
import play.libs.Json;
|
||||||
|
import play.mvc.Http;
|
||||||
|
import play.mvc.Result;
|
||||||
|
import play.test.WithApplication;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static play.mvc.Http.Status.OK;
|
||||||
|
import static play.test.Helpers.*;
|
||||||
|
|
||||||
|
public class StudentControllerUnitTest extends WithApplication {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Application provideApplication() {
|
||||||
|
return new GuiceApplicationBuilder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenStudentPostData_whenCreatingStudent_ThenShouldReturnCreatedStudent() {
|
||||||
|
final ObjectNode jsonNode = Json.newObject();
|
||||||
|
jsonNode.put("firstName", "John");
|
||||||
|
jsonNode.put("lastName", "Baeldung");
|
||||||
|
jsonNode.put("age", 25);
|
||||||
|
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(POST)
|
||||||
|
.bodyJson(jsonNode)
|
||||||
|
.uri("/");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
assertEquals(CREATED, result.status());
|
||||||
|
assertTrue(result.contentType().isPresent());
|
||||||
|
assertEquals("application/json", result.contentType().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenUrlToListStudents_whenListingStudents_ThenShouldReturnStudentList() {
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(GET)
|
||||||
|
.uri("/");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
assertEquals(OK, result.status());
|
||||||
|
assertTrue(result.contentType().isPresent());
|
||||||
|
assertEquals("application/json", result.contentType().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenUrlToRetrieveSingleStudent_whenRetrievingStudent_ThenShouldReturn404NotFound() {
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(GET)
|
||||||
|
.uri("/1");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
assertEquals(NOT_FOUND, result.status());
|
||||||
|
assertTrue(result.contentType().isPresent());
|
||||||
|
assertEquals("application/json", result.contentType().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenUrlToUpdateStudent_whenaUpdatingStudent_ThenShouldFail() {
|
||||||
|
final ObjectNode jsonNode = Json.newObject();
|
||||||
|
jsonNode.put("firstName", "John");
|
||||||
|
jsonNode.put("lastName", "Baeldung");
|
||||||
|
jsonNode.put("age", 25);
|
||||||
|
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(PUT)
|
||||||
|
.bodyJson(jsonNode)
|
||||||
|
.uri("/");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
assertEquals(INTERNAL_SERVER_ERROR, result.status());
|
||||||
|
assertTrue(result.contentType().isPresent());
|
||||||
|
assertEquals("application/json", result.contentType().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenIdToDeleteStudent_whenDeletingStudent_ThenShouldFail() {
|
||||||
|
Http.RequestBuilder request = new Http.RequestBuilder()
|
||||||
|
.method(DELETE)
|
||||||
|
.uri("/1");
|
||||||
|
|
||||||
|
Result result = route(app, request);
|
||||||
|
assertEquals(NOT_FOUND, result.status());
|
||||||
|
assertTrue(result.contentType().isPresent());
|
||||||
|
assertEquals("application/json", result.contentType().get());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue