{"id":20718504,"url":"https://github.com/knowm/xdropwizard","last_synced_at":"2025-04-05T09:09:34.649Z","repository":{"id":7610157,"uuid":"8968341","full_name":"knowm/XDropWizard","owner":"knowm","description":"A skeleton DropWizard Web Application integrating several useful open source projects","archived":false,"fork":false,"pushed_at":"2025-02-21T12:57:02.000Z","size":2418,"stargazers_count":114,"open_issues_count":3,"forks_count":23,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-29T08:11:06.465Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/knowm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-03-23T09:50:16.000Z","updated_at":"2025-01-05T19:05:07.000Z","dependencies_parsed_at":"2024-04-24T14:09:37.265Z","dependency_job_id":"bc858897-6f27-4022-ab55-10e1f5be7581","html_url":"https://github.com/knowm/XDropWizard","commit_stats":{"total_commits":157,"total_committers":6,"mean_commits":"26.166666666666668","dds":0.5031847133757962,"last_synced_commit":"65c31dcd39a698ec63e79282cc90781cd4d10bf6"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowm%2FXDropWizard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowm%2FXDropWizard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowm%2FXDropWizard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowm%2FXDropWizard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/knowm","download_url":"https://codeload.github.com/knowm/XDropWizard/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247312082,"owners_count":20918344,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-17T03:13:51.744Z","updated_at":"2025-04-05T09:09:34.625Z","avatar_url":"https://github.com/knowm.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# XDropWizard\n\nA jump-start [DropWizard](https://github.com/dropwizard/dropwizard) Web Application integrating and demonstrating several useful open source projects such as Yank, Sundial (a Quartz fork), Bower, Flot JS Charts, Angular-nvD3 JS Charts, Bootstrap, AngularJS, HSQLDB, XChart Bitmap Charts, JUnit, etc. Demonstrates how to serve static content, dynamic content loaded into Freemarker templates, using AJAX and more...\n\n![Screenshot of Dashboard](https://raw.githubusercontent.com/timmolter/XDropWizard/master/etc/xdropwizard.png)\n\n## Features\n\n* [x] Uses Dropwizard for web application\n* [x] Uses Bootstrap for looks\n* [x] Uses AngularJS for MVC\n* [x] Uses Sundial for Job scheduling\n* [x] Uses Yank for databases\n* [x] Uses XChart for Bitmap charts\n* [x] Uses Flot for Javascript charts\n* [x] Uses Angular-nvD3 for Javascript charts\n* [x] Uses Freemarker for dynamic templating\n* [x] Uses Bower for front end dependency management\n* [x] Demonstrates working Dropwizard setup\n* [x] Demonstrates Asynchronous Requests/Responses\n* [x] Demonstrates Dropwizard tasks\n* [x] Demonstrates Dropwizard healthchecks\n* [x] Demonstrates Dropwizard Basic Authentication\n* [x] Demonstrates Dropwizard building and deploying\n* [x] Java 7 and up\n* [x] Apache 2.0 license\n\n## Banner Generator\n\nIf you want DropWizard to print out a banner in the console during app startup, you can add a file called `banner.txt` in `src/main/resources`. Use the following link to generate a banner:\n\nhttp://www.webestools.com/ascii-text-generator-ascii-art-code-online-txt2ascii-text2ascii-maker-free-text-to-ascii-converter.html\n\n## Running in Eclipse\n\nRun `XDropWizardApplication` in Eclipse. Add a program arg: `server xdropwizard.yml`.\n\n## Running in IntelliJ\n\nRun `XDropWizardApplication` in IntelliJ. Add a program arg: `server xdropwizard.yml`.\n\n### File `xdropwizard.yml` not found\n\nYou need to set the working directory to `XDropWizard` for the app in IntelliJ (Run ==\u003e Edit Configurations...).\n\n## Terminal\n\n    cd ~/path/to/project/XDropWizard\n\n## Build\n\n    mvn clean package\n\n## Run\n\n    $ java -jar target/xdropwizard.jar server xdropwizard.yml\n\n## Visit Web App\n\n\u003chttp://localhost:9090\u003e\n\n## Test Basics\n\n    http://localhost:9090/service/hello-world\n    http://localhost:9090/admin/\n    http://localhost:9090/admin/healthcheck\n\n## Run Tasks\n\n    curl -X POST http://localhost:9090/admin/tasks/gc\n\n## Static Content\n\nServing static content such as images, html, css, javascript and binary files from you XDropWizard Webservice is possible in addition to the normal JSON resources\ntypical for a webservice. DropWizard names static content as \"Assets\" and all you need to do is place them on the classpath in a folder called `assets`. In our case\nwe simply add the `assets` folder to `src/main/resources` and Maven takes care of adding the folder and its contents to the classpath during the build.\n\nEither your service or your static assets can be served from the root path, but not both. The latter is useful when using Dropwizard to back a Javascript application\nas is the case with XDropWizard. To enable it, move your service to a sub-URL. Note that all webservice calls will now need `service` at the root of the URL. This only applies to the\nnon-admin port however.\n\n    http:\n      rootPath: /service/*  # Default is /*\n\nThen use an extended AssetsBundle constructor to serve resources in the assets folder from the root path. `index.htm` is served as the default page. You need to include the following\nline of code in the `Service` class in the `initialize` method:\n\n    bootstrap.addBundle(new AssetsBundle(\"/assets/\", \"/\"));\n\nIn order to keep the `assets` folder a bit organized, we can add subfolders to it. Our `assets` folder contains `img`, `js`, and `css` subfolders. Our `assets` folder also contains\na special-case file called `index.htm`. By default, DropWizard serves this as the default HTML page.\n\n### Static Content Access\n\nFinally, once DropWizard is running, you can access the static content via the following URLS:\n\n    http://localhost:9090\n    http://localhost:9090/img/favicon.png\n    http://localhost:9090/img/logo_60.png\n    http://localhost:9090/css/main.css\n    http://localhost:9090/sample.html\n\nBTW, the HTML file `index.html` contains all the links referenced in this README file providing a nice overview of all the demonstrated functionality. If you run this\nDropWizard application as described above, you should be able to click on all the links displayed on `index.html` at the following URL:\n\n    http://localhost:9090\n\n### Another Option\n\nAnother approach is to serve all static content from a webserver such as Apache HTTP or nginx, placed in front of the DropWizard instance. This however has the disadvantage\nof spreading your app's content over several places, and the configuration and maintenance is more complex. In certain cases it may make sense though. Gary Rowe blogged\nabout how it can be done with nginx [here](http://gary-rowe.com/agilestack/2013/02/13/an-nginx-config-file-for-dropwizard-with-static-content/).\n\n## Sundial\n\nSundial is a lightweight Java job scheduling framework. Read all about it here: [https://github.com/timmolter/Sundial](https://github.com/timmolter/Sundial).\n\nIntegrating [Sundial](https://github.com/timmolter/Sundial) into a DropWizard instance requires minimal setup, and once it's all configured and running,\nthe scheduling and automatic running of jobs is straight forward and stable. For those not familiar with Sundial, it is a simplified fork of [Quartz](http://quartz-scheduler.org/)\ndeveloped by [Knowm](http://knowm.org/open-source/). A lot of the bloat and confusion of configuring Quartz was removed in creating Sundial and a convenient wrapper around jobs was added to enable\nmore modular job building and organization. Sundial creates a threadpool on application startup and uses it for background jobs.\n\nIntegration is made convenient with the [dropwizard-sundial project](https://github.com/timmolter/dropwizard-sundial).\n\n\n## Adding the dropwizard-sundial dependency\n\nAdd the **dropwizard-sundial** library as a dependency to your `pom.xml` file:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.knowm\u003c/groupId\u003e\n    \u003cartifactId\u003edropwizard-sundial\u003c/artifactId\u003e\n    \u003cversion\u003e4.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Integrate Sundial into you App\n\n\n1. Add the Sundial Bundle in the initialize method.\n\n```java\n@Override\npublic void initialize(Bootstrap\u003cXDropWizardApplicationConfiguration\u003e bootstrap) {\n\n    ...\n\n    bootstrap.addBundle(new SundialBundle\u003cXDropWizardApplicationConfiguration\u003e() {\n\n      @Override\n      public SundialConfiguration getSundialConfiguration(XDropWizardApplicationConfiguration configuration) {\n        return configuration.getSundialConfiguration();\n      }\n    });\n}\n```\n\n2. Add `SundialConfiguration` to your configuration file.\n\n```java\n// Sundial\n@Valid\n@NotNull\npublic SundialConfiguration sundialConfiguration = new SundialConfiguration();\n\n@JsonProperty(\"sundial\")\npublic SundialConfiguration getSundialConfiguration() {\n\n    return sundialConfiguration;\n}\n```\n\n## Create a Job Class\n\n```java\npublic class SampleJob extends org.knowm.sundial.Job {\n\n  @Override\n  public void doRun() throws JobInterruptException {\n    // Do something interesting...\n  }\n}\n```\n\n##  ...with CronTrigger or SimpleTrigger Annotation\n```java\n@CronTrigger(cron = \"0/5 * * * * ?\")\n```\n```java\n@SimpleTrigger(repeatInterval = 30, timeUnit = TimeUnit.SECONDS)\n```\n\n## Alternatively, Put an XML File Called jobs.xml on Classpath\n\n```xml\n\u003c?xml version='1.0' encoding='utf-8'?\u003e\n\u003cjob-scheduling-data\u003e\n\n    \u003cschedule\u003e\n\n        \u003c!-- job with cron trigger --\u003e\n        \u003cjob\u003e\n            \u003cname\u003eSampleJob3\u003c/name\u003e\n            \u003cjob-class\u003ecom.foo.bar.jobs.SampleJob3\u003c/job-class\u003e\n            \u003cconcurrency-allowed\u003etrue\u003c/concurrency-allowed\u003e\n        \u003c/job\u003e\n        \u003ctrigger\u003e\n            \u003ccron\u003e\n                \u003cname\u003eSampleJob3-Trigger\u003c/name\u003e\n                \u003cjob-name\u003eSampleJob3\u003c/job-name\u003e\n                \u003ccron-expression\u003e*/15 * * * * ?\u003c/cron-expression\u003e\n            \u003c/cron\u003e\n        \u003c/trigger\u003e\n\n        \u003c!-- job with simple trigger --\u003e\n        \u003cjob\u003e\n            \u003cname\u003eSampleJob2\u003c/name\u003e\n            \u003cjob-class\u003ecom.foo.bar.jobs.SampleJob2\u003c/job-class\u003e\n            \u003cjob-data-map\u003e\n                \u003centry\u003e\n                    \u003ckey\u003eMyParam\u003c/key\u003e\n                    \u003cvalue\u003e42\u003c/value\u003e\n                \u003c/entry\u003e\n            \u003c/job-data-map\u003e\n        \u003c/job\u003e\n        \u003ctrigger\u003e\n            \u003csimple\u003e\n                \u003cname\u003eSampleJob2-Trigger\u003c/name\u003e\n                \u003cjob-name\u003eSampleJob2\u003c/job-name\u003e\n                \u003crepeat-count\u003e5\u003c/repeat-count\u003e\n                \u003crepeat-interval\u003e5000\u003c/repeat-interval\u003e\n            \u003c/simple\u003e\n        \u003c/trigger\u003e\n\n    \u003c/schedule\u003e\n\n\u003c/job-scheduling-data\u003e\n```\n\n\n### SampleJob3.java\n\nThis job is slightly more complicated and it demonstrates two nice features of Sundial. First it logs the value for myParam which it gets from jobs.xml.\nSecond it uses a `JobAction` and passes it a parameter via the `JobContext`. Using `JobAction`s is a good way to reuse common job actions across many different\njobs, mixing and matching if desired. This keeps your jobs organized.\n\n```java\n    public class SampleJob3 extends Job {\n\n      private final Logger logger = LoggerFactory.getLogger(SampleJob3.class);\n\n      @Override\n      public void doRun() throws JobInterruptException {\n\n        JobContext context = getJobContext();\n\n        String valueAsString = context.get(\"MyParam\");\n        logger.info(\"valueAsString = \" + valueAsString);\n\n        Integer valueAsInt = Integer.valueOf(valueAsString);\n        logger.info(\"valueAsInt = \" + valueAsInt);\n\n        context.put(\"MyValue\", new Integer(123));\n\n        new SampleJobAction().run();\n\n      }\n    }\n```\n\nIn your `*.yml` DropWizard configuration file, you can easily set some helpful parameters to customize Sundial as DropWizard starts up, right from the config file:\n\n```yml\nsundial:\n\n    thread-pool-size: 5\n    shutdown-on-unload: true\n    start-delay-seconds: 0\n    start-scheduler-on-load: true\n    global-lock-on-load: false\n    annotated-jobs-package-name: com.foo.bar.jobs\n```\n\n### Sundial Asynchronous Control via HTTP\n\nBy defining some tasks and hooking them into DropWizard you can asynchronously trigger your jobs and/or put a global lock and unlock on the Sundial scheduler.\n\n    curl -X POST http://localhost:9090/admin/tasks/locksundialscheduler\n    curl -X POST http://localhost:9090/admin/tasks/unlocksundialscheduler\n    curl -X POST \"http://localhost:9090/admin/tasks/startjob?JOB_NAME=MyJob\"\n    curl -X POST \"http://localhost:9090/admin/tasks/startjob?JOB_NAME=SampleJob3\u0026MyParam=9999\"\n    curl -X POST \"http://localhost:9090/admin/tasks/stopjob?JOB_NAME=SampleJob3\"\n    curl -X POST \"http://localhost:9090/admin/tasks/removejob?JOB_NAME=SampleJob3\"\n    curl -X POST \"http://localhost:9090/admin/tasks/addjob?JOB_NAME=SampleJob3\u0026JOB_CLASS=org.knowm.xdropwizard.jobs.SampleJob3\u0026MyParam=888\"\n    curl -X POST http://localhost:9090/admin/tasks/removejobtrigger?TRIGGER_NAME=SampleJob3-Trigger\n    curl -X POST \"http://localhost:9090/admin/tasks/addcronjobtrigger?TRIGGER_NAME=SampleJob3-Trigger\u0026JOB_NAME=SampleJob3\u0026CRON_EXPRESSION=0/45%20*%20*%20*%20*%20?\"\n    curl -X POST \"http://localhost:9090/admin/tasks/addcronjobtrigger?TRIGGER_NAME=SampleJob3-Trigger\u0026JOB_NAME=SampleJob3\" --data-urlencode \"CRON_EXPRESSION=0/45 * * * * ?\"\n    \n**Note:** If you intend to asynchronously stop jobs, read this: The Job termination mechanism works by setting a flag that the Job should be terminated, \nbut it is up to the logic in the Job to decide at what point termination should occur. Therefore, in any long-running job that you anticipate the need to terminate, \nput the method call checkTerminated() at an appropriate location.\n\n### Inject Global Objects or Config Parameters into a Job\n\nYou may want access to a global object such as a REST client, and you don't want to have to reinstantiate that object every single time the job is run. It can be done quite easily by \nputting the object in the ServletContext during app startup in the `run` method. Since Sundial is bound to the ServletContext's lifecycle, it has direct access to the ServletContext. \nThe ServletContext has a `String, Object` map for holding these global objects. The following code snippets show how to add an object to the ServletContext in the `run` method and how \nto access it from a job.\n\n```java\n@Override\npublic void run(XDropWizardApplicationConfiguration configuration, Environment environment) throws Exception {\n\n  logger.info(\"running DropWizard!\");\n\n  // Add object to ServletContext for accessing from Sundial Jobs\n  environment.getApplicationContext().setAttribute(\"MyKey\", \"MyObject\");\n    \n  ...\n}\n```\n\n```java\n@CronTrigger(cron = \"0/25 * * * * ?\")\npublic class MyJob extends Job {\n\n  private final Logger logger = LoggerFactory.getLogger(MyJob.class);\n\n  @Override\n  public void doRun() throws JobInterruptException {\n\n    // pull object from ServletContext, which was added in the apllication's run method\n    String myObject = (String) SundialJobScheduler.getServletContext().getAttribute(\"MyKey\");\n\n    logger.info(\"MyJob says: \" + myObject);\n  }\n}\n```\n\n## Yank\n\nYank is a very easy-to-use yet flexible Java persistence layer for JDBC-compatible databases build on top of\n[org.apache.DBUtils](http://commons.apache.org/dbutils/). Usage is very simple: define DB connectivity properties, create a DAO and POJO class,\nand execute queries.\n\nIntegrating Yank into DropWizard requires just a minimum of setup.\n\n### DB.properties\n\nThe `DB.properties` file should be a familiar sight for people used to working with JDBC-compatible databases such as MySQL, HSQLDB, Oracle, and Postgres.\nPut a file called `DB.properties` on your classpath. See `DB.properties` in `src/main/resources`. In this file, you define the properties needed to connect to your\ndatabase such as the JDBC driver class name, the user and password. Yank will load this file at startup and handle connecting to the database.\n\n### SQL.properties (Optional)\n\nPut a file called `SQL.properties` on your classpath. See `SQL.properties` in `src/main/resources`. The `SQL.properties` file is a place to centrally store your\nSQL statements. There are a few advantages to this. First, all your statements are found at a single place so you can see tham all at once. Secondly, if you want\nto switch your underlying database you'll need to rewrite all your SQL statements. If you have a `SQL.properties` file, you can just create a second one for the new\ndatabase and easily make the transition. Of course, you can write all your SQL statements in the Java DAO classes directly as well.\n\n### Book.java\n\nYank requires that you have a single POJO for each table in your database. The POJO's fields should match the column names and data types of the matching table.\nAdd the getter and setters as well.\n\n```java\npublic class Book {\n\n  private String title;\n  private String author;\n  private double price;\n\n  /** Pro-tip: In Eclipse, generate all getters and setters after defining class fields: Right-click --\u003e Source --\u003e Generate Getters and Setters... */\n\n  public String getTitle() {\n    return title;\n  }\n\n  public void setTitle(String title) {\n    this.title = title;\n  }\n\n  public String getAuthor() {\n    return author;\n  }\n\n  public void setAuthor(String author) {\n    this.author = author;\n  }\n\n  public double getPrice() {\n    return price;\n  }\n\n  public void setPrice(double price) {\n    this.price = price;\n  }\n\n}\n```\n\n### BooksDAO.java\n\nIt is not required by Yank, but it really helps to organize your persistence layer code to have one DAO class for each table. The DAO class is just a collection\nof public static methods that each interact with Yank's `DBProxy` class. Note that in some of the following methods, the SQL statements are written directly as a\nString, while others come from the `SQL.properties` file on the classpath. The presence of the word `key` in the `DBProxy` method indicates that the SQL\nstatement is being fetched from the `SQL.properties`.\n\n```java\npublic class BooksDAO {\n\n  public static int createBooksTable() {\n\n    String sqlKey = \"BOOKS_CREATE_TABLE\";\n    return DBProxy.executeSQLKey(\"myconnectionpoolname\", sqlKey, null);\n  }\n\n  public static int insertBook(Book book) {\n\n    Object[] params = new Object[] { book.getTitle(), book.getAuthor(), book.getPrice() };\n    String SQL = \"INSERT INTO BOOKS  (TITLE, AUTHOR, PRICE) VALUES (?, ?, ?)\";\n    return DBProxy.executeSQL(\"myconnectionpoolname\", SQL, params);\n  }\n\n  public static List\u003cBook\u003e selectAllBooks() {\n\n    String SQL = \"SELECT * FROM BOOKS\";\n    return DBProxy.queryObjectListSQL(\"myconnectionpoolname\", SQL, Book.class, null);\n  }\n\n  public static Book selectRandomBook() {\n\n    String sqlKey = \"BOOKS_SELECT_RANDOM_BOOK\";\n    return DBProxy.querySingleObjectSQLKey(\"myconnectionpoolname\", sqlKey, Book.class, null);\n  }\n\n}\n```\n\n### YankBookResource.java\n\nIn order to access objects from the database and return them as JSON, you need a resource class for it. It makes most sense to create a resource class for\neach table in your database. Don't forget to add this resource in the `Service` class!\n\n```java\n@Path(\"book\")\n@Produces(MediaType.APPLICATION_JSON)\npublic class YankBookResource {\n\n  @GET\n  @Path(\"random\")\n  public Book getRandomBook() {\n\n    return BooksDAO.selectRandomBook();\n  }\n\n  @GET\n  @Path(\"all\")\n  public List\u003cBook\u003e getAllBooks() {\n\n    return BooksDAO.selectAllBooks();\n  }\n}\n```\n\n### YankManager.java\n\n`YankManager.java` is the class responsible for setting up `Yank` and it is hooked into DropWizard in the `Service` class by\nincluding the following line of code:\n\n```java\n    YankManager ym = new YankManager(configuration.getYankConfiguration()); // A DropWizard Managed Object\n    environment.manage(ym); // Assign the management of the object to the Service\n    environment.addResource(new YankBookResource());\n```\n\nIn your `.yml` DropWizard configuration file, you can easily define the connection pools and SQL statement files that Yank uses:\n\n```\nyank:\n  -\n    dbPropsFileName: DB.properties\n    sqlPropsFileName: SQL.properties\n  -\n    poolName: mypool\n    dbPropsFileName: DB.properties\n    sqlPropsFileName: SQL.properties\n```\n\n### Yank Database Access\n\nFinally, once DropWizard is running, you can access the JSON objects via the following URLS:\n\n    http://localhost:9090/service/book/random\n    http://localhost:9090/service/book/all\n\n## XChart\n\n[XChart](https://github.com/timmolter/XChart) is a light-weight and convenient library for plotting data. We use it in Dropwizard to dynamically create line,\nscatter, and bar charts and to provide the resulting bitmaps (PNGs, JPGs, etc.) as URL endpoint resources.\n\nThere is no required setup or initialization as in the case with Sundial and Yank. You only need to create a resource for each chart you are providing.\n\n### XChartResource.java\n\nThis example XChartResource class creates an XChart `QuickChart` and sends the image as a byte[] using `XChart`'s `BitmapEncoder` class. Don't forget to add this resource in the `Service` class!\n\n```java\n    @Path(\"xchart\")\n    public class XChartResource {\n\n      @GET\n      @Path(\"random.png\")\n      @Produces(\"image/png\")\n      public Response getRandomLineChart() throws IOException {\n\n        Chart chart = QuickChart.getChart(\"XChart Sample - Random Walk\", \"X\", \"Y\", null, null, getRandomWalk(105));\n\n        return Response.ok().type(\"image/png\").entity(BitmapEncoder.getPNGBytes(chart)).build();\n      }\n\n      private double[] getRandomWalk(int numPoints) {\n\n        double[] y = new double[numPoints];\n        for (int i = 1; i \u003c y.length; i++) {\n          y[i] = y[i - 1] + Math.random() - .5;\n        }\n        return y;\n      }\n\n    }\n```\n\n### XChart Image Access\n\nFinally, once DropWizard is running, you can access the XChart plots as PNGs via the following URL:\n\n    http://localhost:9090/service/xchart/random.png\n    http://localhost:9090/xchart.html\n\n## Dynamic HTML Pages\n\nDynamic HTML pages in DropWizard are referred to as \"Views\". These are like dynamic web pages produced by php or jsp/Servlets. Before adding Views to DropWizard\n, you need to include the following line of code in the `Service` class in the `initialize` method:\n\n    bootstrap.addBundle(new ViewBundle());\n\nYou'll also need to add the `dropwizard-views` dependency to the pom.xml file:\n\n```xml\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecom.yammer.dropwizard\u003c/groupId\u003e\n        \u003cartifactId\u003edropwizard-views\u003c/artifactId\u003e\n        \u003cversion\u003ewhatever\u003c/version\u003e\n    \u003c/dependency\u003e\n```\n\n### View Resource\n\nJust as we need a `Resource` class for JSON endpoints, a `Resource` class is needed for \"Views\" too.\n\n```java\n    @Path(\"view/book\")\n    @Produces(MediaType.TEXT_HTML)\n    public class ViewBookResource {\n\n      @GET\n      @Timed\n      @CacheControl(noCache = true)\n      public BookView bookView() {\n\n        return new BookView();\n      }\n\n    }\n```\n\nDon't forget to add this resource in the `Service` class!\n\n### View Class\n\nThe view class provides both the freemaker template and the dynamic data for the page. Here a `Book` object is hardcoded,\nbut it could easily come from a database. Any URL parameters can be passed from the `Resource` to the `View` via its constructor.\n\n```java\n    public class BookView extends View {\n\n      public BookView() {\n\n        super(\"ftl/book.ftl\");\n      }\n\n      public Book getBook() {\n\n        Book book = new Book();\n        book.setTitle(\"Cryptonomicon\");\n        book.setAuthor(\"Neal Stephenson\");\n        book.setPrice(23.99);\n        return book;\n      }\n\n    }\n```\n\n### FTL - FreeMarker Template\n\n`book.ftl` is the path of the template relative to the class name. If this class was `org.knowm.xdropwizard.views.PersonView`, Dropwizard\nwould then look for the file src/main/resources/org/knowm/xdropwizard/views/person.ftl.\n\n```html\n    \u003c!DOCTYPE html\u003e\n    \u003chtml lang=\"en\"\u003e\n    \u003chead\u003e\n    \u003c#include \"../includes/head.ftl\"\u003e\n    \u003c/head\u003e\n\n    \u003cbody\u003e\n\n    \u003cdiv\u003e\n\n        \u003c#include \"../includes/header.ftl\"\u003e\n\n        \u003cdiv id=\"markdown\"\u003e\n        \u003ctable\u003e\n        \u003ctr\u003e\n        \u003ctd\u003eBook Title:\u003c/td\u003e\u003ctd\u003e${book.title}\u003c/td\u003e\u003c/tr\u003e\n        \u003ctr\u003e\u003ctd\u003eBook Author:\u003c/td\u003e\u003ctd\u003e${book.author}\u003c/td\u003e\u003c/tr\u003e\n        \u003ctr\u003e\u003ctd\u003eBook Price:\u003c/td\u003e\u003ctd\u003e${book.price}\u003c/td\u003e\u003c/tr\u003e\n        \u003c/table\u003e\n        \u003c/div\u003e\n\n        \u003c#include \"../includes/footer.ftl\"\u003e\n\n    \u003c/div\u003e\n\n    \u003c#include \"../includes/cdn-scripts.ftl\"\u003e\n\n    \u003c/body\u003e\n    \u003c/html\u003e\n```\n\nNotice the `#include` sections. This allows you to set up common page elements, thus avaoiding copy and pasting header, footer and script sections in all your FTLs.\n\n### Book View Access\n\nSince the view is a `Resource`, we need to include `service` in the URL:\n\n    http://localhost:9090/service/view/book\n\n## AJAX\n\nFor pseudo-real-time updates to an HTML page, AJAX comes in handy. Adding AJAX to a web application requires 2 compnents:\n\n1. an HTML page with a JQuery AJAX query\n1. a backend JSON endpoint\n\n### AJAX HTML page (ajax.html)\n\nThis page uses JQuery to fetch JSON, update contents of the `numberplaceholder` span, and repeat every one second.\n```html\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eSample AJAX Page\u003c/title\u003e\n    \u003c!-- Bootstrap core CSS --\u003e\n    \u003clink href=\"/bower_components/bootstrap/dist/css/bootstrap.min.css\" rel=\"stylesheet\"\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n\n    \u003ch1\u003eSample AJAX HTML Page\u003c/h1\u003e\n    \u003cp\u003eThis is a sample html page demonstrating AJAX.\u003c/p\u003e\n\n    \u003cdiv class=\"github\"\u003e\n        Random Number from Server: \u003cspan id=\"numberplaceholder\"\u003e\u0026nbsp;\u003c/span\u003e\n    \u003c/div\u003e\n\n    \u003cscript src=\"/bower_components/jquery/dist/jquery.js\"\u003e\u003c/script\u003e\n    \u003cscript\u003e\n        $(function() {\n\n            dataUpdate();\n        });\n\n        function dataUpdate() {\n\n            $.getJSON(\"/service/random\", function(json) {\n\n                $('#numberplaceholder').html(json.number);\n                setTimeout('dataUpdate()', 1000);\n\n            }).error(function() {\n                console.log(\"errorfetching JSON asynchronously!\");\n            });\n        }\n    \u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n\n```\n### Backend JSON endpoint (RandomNumberResource.java)\n```java\n@Path(\"random\")\n@Produces(MediaType.APPLICATION_JSON)\npublic class RandomNumberResource {\n\n  @GET\n  public RandomNumber getRandom() {\n\n    return new RandomNumber();\n  }\n}\n```\n\n### AJAX Page Access\n\n    http://localhost:9090/ajax.html\n\n## Flot\n\n[Flot](http://www.flotcharts.org/) is a pure JavaScript plotting library for jQuery, with a focus on simple usage, attractive looks and interactive features. It's\nwonderful for web-based plots.\n\n### jquery.flot.js\n\nIntegrating `flot` into a webapp requires adding the latest `javascript` file(s) from `flot`, which can be grabbed from their [GitHub page](https://github.com/flot/flot/releases).\nWe place the `jquery.flot.js` file into a `js` folder in `src/main.resources`. There are many extra `flot` js files used to add extra functionaity to flot.\n\n### flot.html\n\nThere are just two main things needed to make a flot chart:\n\n1. a link to `jquery.flot.js`\n1. the `placeholder` div\n\n```html\n\u003chtml\u003e\n\n\u003chead\u003e\n  \u003ctitle\u003eSample Flot Page\u003c/title\u003e\n  \u003c!-- Bootstrap core CSS --\u003e\n  \u003clink href=\"/bower_components/bootstrap/dist/css/bootstrap.min.css\" rel=\"stylesheet\"\u003e\n\u003c/head\u003e\n\n\u003cbody\u003e\n\n  \u003ch1\u003eSample Flot HTML Page\u003c/h1\u003e\n  \u003cp\u003eThis is a sample html page demonstrating Flot.\u003c/p\u003e\n\n  \u003cdiv class=\"github notFullWidth\"\u003e\n    \u003cdiv id=\"placeholder\" style=\"width: 600px; height: 400px; font-size: 14px; line-height: 1.2em;\"\u003e\u003c/div\u003e\n  \u003c/div\u003e\n  \u003cscript src=\"/bower_components/jquery/dist/jquery.js\"\u003e\u003c/script\u003e\n  \u003cscript type=\"text/javascript\" src=\"/bower_components/flot/jquery.flot.js\"\u003e\u003c/script\u003e\n  \u003cscript\u003e\n    $(function() {\n\n      var d1 = [];\n      for (var i = 0; i \u003c 14; i += 0.5) {\n        d1.push([i, Math.sin(i)]);\n      }\n\n      $.plot(\"#placeholder\", [d1]);\n\n    });\n  \u003c/script\u003e\n\u003c/body\u003e\n\n\u003c/html\u003e\n\n```\n\n## AngularJS\n\n[AngularJS](https://angularjs.org/) is a Java-script-based thick client providing a model-view-controller framework for web applications.\n\nIntegrating `AngularJS` into a webapp requires adding some Javascript files to the generated HTML and the integration of Javascript acting as the controller (in MVC) between the view (HTML) and the model (the JSON webservice).\n\n### books.html\n```html\n\u003chtml ng-app=\"sampleApp\"\u003e\n\n\u003chead\u003e\n  \u003ctitle\u003eSample AngularJS Page\u003c/title\u003e\n  \u003c!-- Bootstrap core CSS --\u003e\n  \u003clink href=\"/bower_components/bootstrap/dist/css/bootstrap.min.css\" rel=\"stylesheet\"\u003e\n  \u003cscript src=\"/bower_components/angular/angular.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"/js/books_angular.js\"\u003e\u003c/script\u003e\n\u003c/head\u003e\n\n\u003cbody\u003e\n\n  \u003ch1\u003eSample AngularJS Page\u003c/h1\u003e\n  \u003cp\u003eThis is a sample html page demonstrating AngularJS.\u003c/p\u003e\n\n\n  \u003cdiv ng-controller=\"sampleAppController\"\u003e\n    \u003cdiv class=\"container-fluid\"\u003e\n      \u003cdiv class=\"row\"\u003e\n        \u003cdiv class=\"col-sm-3 col-md-2 sidebar\"\u003e\n          \u003ctable class=\"table\"\u003e\n            \u003ctr ng-repeat=\"book in books\"\u003e\n              \u003ctd\u003e{{book.author}}\u003c/td\u003e\n              \u003ctd\u003e{{book.title}}\u003c/td\u003e\n              \u003ctd\u003e{{book.price}}\u003c/td\u003e\n            \u003c/tr\u003e\n          \u003c/table\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\n\u003c/body\u003e\n\n\u003c/html\u003e\n\n```\n### books_angular.js\n\n```javascript\nangular.module('sampleApp', [])\n  .controller('sampleAppController', ['$scope', '$http', function($scope, $http) {\n\n    $scope.books = [];\n\n    $http.get('/service/book/all').success(function(data) {\n      console.log(data);\n      $scope.books = data;\n    }).\n    error(function(data, status, headers, config) {\n      console.log(data);\n    });\n\n  }]);\n```\n\nThe controller defines a dependency to the `$scope` and the `$http` module. An HTTP GET request to the `/service/book/all` endpoint is carried out with the get method. It returns a $promise object with a success and an error method. Once successful, the JSON data is assigned to $scope.books to make it available in the template in books.html. The 'ng-repeat' creates a multi-rowed table to match the data fetched from the backend.\n\n## Bower\n\nBower is used to manage the front end dependencies including JS and CSS libs. It's like Maven, but for front end web technology. Dependencies are defined in `.../assets/bower.json`\n\n### Install Bower\n\nRead all about `bower` in this concise writeup: \u003chttp://blog.teamtreehouse.com/getting-started-bower\u003e\n\n     npm install -g bower\n     \n### Install Front-end Dependencies\n\n    cd ~/path/to/XDropWizard/src/main/resources/assets\n    bower update\n    \nThis will download and put the JS dependencies found in `.../assets/bower.json` into a folder called: `.../assets/bower_components`. You can then reference the JS files in your HTML. The `bower.json` allows to you set specific versions of the dependencies if you want to. Otherwise the `\"*\"` indicates to bower to download the latest version.\nSee `.../assets/books.html` on how to integrate the bower dependencies into an HTML document.\n\nNote that normally you would add the `src/main/resources/assets/bower_components` to your `.gitignore` file and not check these dependencies into your source repository and you would run `bower update` to get those dependencies. For this project I left a lot of the bower-installed files in the repo so this app runs flawlessly out of the box.\n\n## Angular-nvD3\n\n[Angular-nvD3](https://github.com/krispo/angular-nvd3) is designed to make it easier to work with nvd3.js re-usable charting library. The Angular JS directive allows you to easily customize your charts via JSON API. Bower is used to pull in the necessary dependencies with the line: `\"angular-nvd3\": \"latest\"`.\n\nThe `angular-nvd3` project has a fundamental difference from the others in the base approach it is created. This directive provides a two-way binding mechanism for all chart options over the full nvd3 core as well as chart data. It allows you to interactively customize chart options or data from the controller on the fly via JSON.\n\nIntegrating `angular-nvd3` into your app requires a HTML page and a JS file. Here is the second example which pulls data from the webservice:\n\n### nvd3-chart2.html\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml ng-app=\"plunker\"\u003e\n\n  \u003chead\u003e\n    \u003cmeta charset=\"utf-8\"\u003e  \u003c!-- it's important for d3.js --\u003e\n    \u003ctitle\u003eAngular-nvD3 Line Chart 2\u003c/title\u003e\n    \u003clink href=\"/bower_components/bootstrap/dist/css/bootstrap.min.css\" rel=\"stylesheet\"\u003e\n    \u003cscript src=\"/bower_components/angular/angular.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"/bower_components/d3/d3.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"/bower_components/nvd3/build/nv.d3.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"/bower_components/angular-nvd3/dist/angular-nvd3.js\"\u003e\u003c/script\u003e\n    \u003clink rel=\"stylesheet\" href=\"bower_components/nvd3/build/nv.d3.css\"\u003e\n    \u003cscript src=\"/js/nvd3-chart2.js\"\u003e\u003c/script\u003e\n    \n  \u003c/head\u003e\n\n  \u003cbody ng-controller=\"MainCtrl\"\u003e\n  \n  \n    \u003ch1\u003eSample Angular-nvD3 HTML Page\u003c/h1\u003e\n    \u003cp\u003eThis is a sample html page demonstrating Angular-nvD3 with data fetched from server.\u003c/p\u003e\n    \n    \u003cnvd3 options=\"options\" data=\"appChartData\" ng-init=\"initChartData()\"\u003e\u003c/nvd3\u003e\n    \n  \u003c/body\u003e\n\n\u003c/html\u003e\n```\n\n### nvd3-chart2.js\n\n```javascript\nvar app = angular.module('plunker', ['nvd3']);\n\napp.controller('MainCtrl', function($scope, $http) {\n  $scope.options = {\n            chart: {\n                type: 'lineChart',\n                height: 450,\n                margin : {\n                    top: 20,\n                    right: 20,\n                    bottom: 40,\n                    left: 55\n                },\n                x: function(d){ return d.x; },\n                y: function(d){ return d.y; },\n                xAxis: {\n                    axisLabel: 'X'\n                },\n                yAxis: {\n                    axisLabel: 'Y',\n                    tickFormat: function(d){\n                        return d3.format('.02f')(d);\n                    },\n                    axisLabelDistance: 30\n                },\n                callback: function(chart){\n                    console.log(\"!!! lineChart callback !!!\");\n                }\n            },\n            title: {\n                enable: true,\n                text: 'X vs. Y'\n            }\n        };\n  \n  \n//////////////////////////////////////////////////////////////////////\n  \n    // Chart Data //////////////////////////////////////////////////////////////\n    \n    \n    $scope.initChartData = function() {\n        \n        $http.get('/service/nvd3data/chartdata').success(function(data) {\n            \n//          console.log(data);\n            \n            $scope.appChartData = [\n                                   convertToChartFormat(data.xAxisData, data.a, 'A'),\n                                   convertToChartFormat(data.xAxisData, data.b, 'B'),\n                                   convertToChartFormat(data.xAxisData, data.c, 'C'),\n                                   convertToChartFormat(data.xAxisData, data.d, 'D')\n                                   ];\n\n//          console.log($scope.appChartData);\n        });\n\n    };\n\n//////////////////////////////////////////////////////////////////////\n\n\n});\n\n\nfunction convertToChartFormat(xData, yData, seriesName){\n    \n    var returnValue;\n    \n    var convertedChartArray = [];\n    var i;\n    for (i = 0; i \u003c xData.length; i++) {\n        convertedChartArray.push( {x: xData[i], y: yData[i]});\n\n    }\n    returnValue = {\n        key: seriesName,\n        values: convertedChartArray\n    }\n    return returnValue;\n};\n\n```\n\n\n## Asynchronous Requests/Responses\n\nFor long running Asynchronous requests and responses, we can use Jersey's [Asynchronous Services and Clients](https://jersey.java.net/documentation/latest/async.html).\n\n### Server Endpoint (`AsyncResource.java`)\n\n```java\n\n@Path(\"/async\")\npublic class AsyncResource {\n\n  private static int numberOfSuccessResponses = 0;\n  private static int numberOfFailures = 0;\n  private static Throwable lastException = null;\n\n  @GET\n  public void asyncGetWithTimeout(@Suspended final AsyncResponse asyncResponse) {\n    asyncResponse.register(new CompletionCallback() {\n      @Override\n      public void onComplete(Throwable throwable) {\n        if (throwable == null) {\n          // no throwable - the processing ended successfully\n          // (response already written to the client)\n          numberOfSuccessResponses++;\n        } else {\n          numberOfFailures++;\n          lastException = throwable;\n        }\n      }\n    });\n    new Thread(new Runnable() {\n      @Override\n      public void run() {\n        String result = veryExpensiveOperation();\n        asyncResponse.resume(result);\n      }\n\n      private String veryExpensiveOperation() {\n        // ... very expensive operation\n        try {\n          Thread.sleep(5000);\n        } catch (InterruptedException e) {\n          e.printStackTrace();\n        }\n        return \"Hello Async!\";\n      }\n    }).start();\n  }\n}\n\n```\n\n### Client (`AsyncTest.java`)\n\n```java\n\npublic class AsyncTest {\n\n  public static void main(String[] args) throws InterruptedException, ExecutionException {\n\n    AsyncTest asyncTest = new AsyncTest();\n    asyncTest.go();\n  }\n\n  private void go() throws InterruptedException, ExecutionException {\n\n    Client client = ClientBuilder.newClient();\n\n    final Future\u003cString\u003e entityFuture = client.target(\"http://localhost:9090/service/async\").request().async().get(new InvocationCallback\u003cString\u003e() {\n      @Override\n      public void completed(String response) {\n        System.out.println(\"Response entity '\" + response + \"' received.\");\n      }\n\n      @Override\n      public void failed(Throwable throwable) {\n        System.out.println(\"Invocation failed.\");\n        throwable.printStackTrace();\n      }\n    });\n    System.out.println(entityFuture.get());\n\n  }\n\n}\n\n```\n\n## File Upload\n\nTo add file uploading capabilities to your webapp using DropWizard (and Jersey) there are a couple of preliminary steps you needs to take first:\n\n1. Add `bootstrap.addBundle(new MultiPartBundle());` to your `initialize()` method in your `Application` class\n1. Add the `dropwizard-forms` dependency to the `pom` file\n\n### Resource (`FileUploadResource.java`)\n\n```java\n@Path(\"/file\")\n@Produces(MediaType.APPLICATION_JSON)\npublic class FileUploadResource {\n\n  private final Logger logger = LoggerFactory.getLogger(FileUploadResource.class);\n\n  @POST\n  @Path(\"/upload\")\n  @Consumes(MediaType.MULTIPART_FORM_DATA)\n  public Response uploadFile(@FormDataParam(\"file\") InputStream uploadedInputStream, @FormDataParam(\"file\") FormDataContentDisposition fileDetail) {\n\n    String fileName = fileDetail.getFileName();\n\n    String output = \"File received : \" + fileName;\n\n    logger.info(output);\n\n    return Response.status(200).entity(output).build();\n  }\n\n}\n\n```\n\nFinally, once DropWizard is running, you can post a file via a form the following URL:\n\nhttp://localhost:9090/fileupload.html\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fknowm%2Fxdropwizard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fknowm%2Fxdropwizard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fknowm%2Fxdropwizard/lists"}