}` –
88 | * transform function or an array of such functions. The transform function takes the http
89 | * response body and headers and returns its transformed (typically deserialized) version.
90 | * - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
91 | * GET request, otherwise if a cache instance built with
92 | * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
93 | * caching.
94 | * - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that
95 | * should abort the request when resolved.
96 | * - **`withCredentials`** - `{boolean}` - whether to to set the `withCredentials` flag on the
97 | * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
98 | * requests with credentials} for more information.
99 | * - **`responseType`** - `{string}` - see {@link
100 | * https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
101 | * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
102 | * `response` and `responseError`. Both `response` and `responseError` interceptors get called
103 | * with `http response` object. See {@link ng.$http $http interceptors}.
104 | *
105 | * @returns {Object} A resource "class" object with methods for the default set of resource actions
106 | * optionally extended with custom `actions`. The default set contains these actions:
107 | *
108 | * { 'get': {method:'GET'},
109 | * 'save': {method:'POST'},
110 | * 'query': {method:'GET', isArray:true},
111 | * 'remove': {method:'DELETE'},
112 | * 'delete': {method:'DELETE'} };
113 | *
114 | * Calling these methods invoke an {@link ng.$http} with the specified http method,
115 | * destination and parameters. When the data is returned from the server then the object is an
116 | * instance of the resource class. The actions `save`, `remove` and `delete` are available on it
117 | * as methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
118 | * read, update, delete) on server-side data like this:
119 | *
120 | var User = $resource('/user/:userId', {userId:'@id'});
121 | var user = User.get({userId:123}, function() {
122 | user.abc = true;
123 | user.$save();
124 | });
125 |
126 | *
127 | * It is important to realize that invoking a $resource object method immediately returns an
128 | * empty reference (object or array depending on `isArray`). Once the data is returned from the
129 | * server the existing reference is populated with the actual data. This is a useful trick since
130 | * usually the resource is assigned to a model which is then rendered by the view. Having an empty
131 | * object results in no rendering, once the data arrives from the server then the object is
132 | * populated with the data and the view automatically re-renders itself showing the new data. This
133 | * means that in most case one never has to write a callback function for the action methods.
134 | *
135 | * The action methods on the class object or instance object can be invoked with the following
136 | * parameters:
137 | *
138 | * - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
139 | * - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
140 | * - non-GET instance actions: `instance.$action([parameters], [success], [error])`
141 | *
142 | * Success callback is called with (value, responseHeaders) arguments. Error callback is called
143 | * with (httpResponse) argument.
144 | *
145 | * Class actions return empty instance (with additional properties below).
146 | * Instance actions return promise of the action.
147 | *
148 | * The Resource instances and collection have these additional properties:
149 | *
150 | * - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
151 | * instance or collection.
152 | *
153 | * On success, the promise is resolved with the same resource instance or collection object,
154 | * updated with data from server. This makes it easy to use in
155 | * {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view rendering
156 | * until the resource(s) are loaded.
157 | *
158 | * On failure, the promise is resolved with the {@link ng.$http http response} object,
159 | * without the `resource` property.
160 | *
161 | * - `$resolved`: `true` after first server interaction is completed (either with success or rejection),
162 | * `false` before that. Knowing if the Resource has been resolved is useful in data-binding.
163 | *
164 | * @example
165 | *
166 | * # Credit card resource
167 | *
168 | *
169 | // Define CreditCard class
170 | var CreditCard = $resource('/user/:userId/card/:cardId',
171 | {userId:123, cardId:'@id'}, {
172 | charge: {method:'POST', params:{charge:true}}
173 | });
174 |
175 | // We can retrieve a collection from the server
176 | var cards = CreditCard.query(function() {
177 | // GET: /user/123/card
178 | // server returns: [ {id:456, number:'1234', name:'Smith'} ];
179 |
180 | var card = cards[0];
181 | // each item is an instance of CreditCard
182 | expect(card instanceof CreditCard).toEqual(true);
183 | card.name = "J. Smith";
184 | // non GET methods are mapped onto the instances
185 | card.$save();
186 | // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
187 | // server returns: {id:456, number:'1234', name: 'J. Smith'};
188 |
189 | // our custom method is mapped as well.
190 | card.$charge({amount:9.99});
191 | // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
192 | });
193 |
194 | // we can create an instance as well
195 | var newCard = new CreditCard({number:'0123'});
196 | newCard.name = "Mike Smith";
197 | newCard.$save();
198 | // POST: /user/123/card {number:'0123', name:'Mike Smith'}
199 | // server returns: {id:789, number:'01234', name: 'Mike Smith'};
200 | expect(newCard.id).toEqual(789);
201 | *
202 | *
203 | * The object returned from this function execution is a resource "class" which has "static" method
204 | * for each action in the definition.
205 | *
206 | * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and `headers`.
207 | * When the data is returned from the server then the object is an instance of the resource type and
208 | * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
209 | * operations (create, read, update, delete) on server-side data.
210 |
211 |
212 | var User = $resource('/user/:userId', {userId:'@id'});
213 | var user = User.get({userId:123}, function() {
214 | user.abc = true;
215 | user.$save();
216 | });
217 |
218 | *
219 | * It's worth noting that the success callback for `get`, `query` and other method gets passed
220 | * in the response that came from the server as well as $http header getter function, so one
221 | * could rewrite the above example and get access to http headers as:
222 | *
223 |
224 | var User = $resource('/user/:userId', {userId:'@id'});
225 | User.get({userId:123}, function(u, getResponseHeaders){
226 | u.abc = true;
227 | u.$save(function(u, putResponseHeaders) {
228 | //u => saved user object
229 | //putResponseHeaders => $http header getter
230 | });
231 | });
232 |
233 |
234 | * # Buzz client
235 |
236 | Let's look at what a buzz client created with the `$resource` service looks like:
237 |
238 |
239 |
259 |
260 |
261 |
262 |
fetch
263 |
264 |
265 |
270 | {{item.object.content | html}}
271 |
275 |
276 |
277 |
278 |
279 |
280 |
281 | */
282 | angular.module('ngResource', ['ng']).
283 | factory('$resource', ['$http', '$parse', '$q', function($http, $parse, $q) {
284 | var DEFAULT_ACTIONS = {
285 | 'get': {method:'GET'},
286 | 'save': {method:'POST'},
287 | 'query': {method:'GET', isArray:true},
288 | 'remove': {method:'DELETE'},
289 | 'delete': {method:'DELETE'}
290 | };
291 | var noop = angular.noop,
292 | forEach = angular.forEach,
293 | extend = angular.extend,
294 | copy = angular.copy,
295 | isFunction = angular.isFunction,
296 | getter = function(obj, path) {
297 | return $parse(path)(obj);
298 | };
299 |
300 | /**
301 | * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
302 | * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
303 | * segments:
304 | * segment = *pchar
305 | * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
306 | * pct-encoded = "%" HEXDIG HEXDIG
307 | * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
308 | * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
309 | * / "*" / "+" / "," / ";" / "="
310 | */
311 | function encodeUriSegment(val) {
312 | return encodeUriQuery(val, true).
313 | replace(/%26/gi, '&').
314 | replace(/%3D/gi, '=').
315 | replace(/%2B/gi, '+');
316 | }
317 |
318 |
319 | /**
320 | * This method is intended for encoding *key* or *value* parts of query component. We need a custom
321 | * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
322 | * encoded per http://tools.ietf.org/html/rfc3986:
323 | * query = *( pchar / "/" / "?" )
324 | * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
325 | * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
326 | * pct-encoded = "%" HEXDIG HEXDIG
327 | * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
328 | * / "*" / "+" / "," / ";" / "="
329 | */
330 | function encodeUriQuery(val, pctEncodeSpaces) {
331 | return encodeURIComponent(val).
332 | replace(/%40/gi, '@').
333 | replace(/%3A/gi, ':').
334 | replace(/%24/g, '$').
335 | replace(/%2C/gi, ',').
336 | replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
337 | }
338 |
339 | function Route(template, defaults) {
340 | this.template = template;
341 | this.defaults = defaults || {};
342 | this.urlParams = {};
343 | }
344 |
345 | Route.prototype = {
346 | setUrlParams: function(config, params, actionUrl) {
347 | var self = this,
348 | url = actionUrl || self.template,
349 | val,
350 | encodedVal;
351 |
352 | var urlParams = self.urlParams = {};
353 | forEach(url.split(/\W/), function(param){
354 | if (!(new RegExp("^\\d+$").test(param)) && param && (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
355 | urlParams[param] = true;
356 | }
357 | });
358 | url = url.replace(/\\:/g, ':');
359 |
360 | params = params || {};
361 | forEach(self.urlParams, function(_, urlParam){
362 | val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
363 | if (angular.isDefined(val) && val !== null) {
364 | encodedVal = encodeUriSegment(val);
365 | url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), encodedVal + "$1");
366 | } else {
367 | url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
368 | leadingSlashes, tail) {
369 | if (tail.charAt(0) == '/') {
370 | return tail;
371 | } else {
372 | return leadingSlashes + tail;
373 | }
374 | });
375 | }
376 | });
377 |
378 | // strip trailing slashes and set the url
379 | url = url.replace(/\/+$/, '');
380 | // then replace collapse `/.` if found in the last URL path segment before the query
381 | // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
382 | url = url.replace(/\/\.(?=\w+($|\?))/, '.');
383 | // replace escaped `/\.` with `/.`
384 | config.url = url.replace(/\/\\\./, '/.');
385 |
386 |
387 | // set params - delegate param encoding to $http
388 | forEach(params, function(value, key){
389 | if (!self.urlParams[key]) {
390 | config.params = config.params || {};
391 | config.params[key] = value;
392 | }
393 | });
394 | }
395 | };
396 |
397 |
398 | function ResourceFactory(url, paramDefaults, actions) {
399 | var route = new Route(url);
400 |
401 | actions = extend({}, DEFAULT_ACTIONS, actions);
402 |
403 | function extractParams(data, actionParams){
404 | var ids = {};
405 | actionParams = extend({}, paramDefaults, actionParams);
406 | forEach(actionParams, function(value, key){
407 | if (isFunction(value)) { value = value(); }
408 | ids[key] = value && value.charAt && value.charAt(0) == '@' ? getter(data, value.substr(1)) : value;
409 | });
410 | return ids;
411 | }
412 |
413 | function defaultResponseInterceptor(response) {
414 | return response.resource;
415 | }
416 |
417 | function Resource(value){
418 | copy(value || {}, this);
419 | }
420 |
421 | forEach(actions, function(action, name) {
422 | var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
423 |
424 | Resource[name] = function(a1, a2, a3, a4) {
425 | var params = {}, data, success, error;
426 |
427 | switch(arguments.length) {
428 | case 4:
429 | error = a4;
430 | success = a3;
431 | //fallthrough
432 | case 3:
433 | case 2:
434 | if (isFunction(a2)) {
435 | if (isFunction(a1)) {
436 | success = a1;
437 | error = a2;
438 | break;
439 | }
440 |
441 | success = a2;
442 | error = a3;
443 | //fallthrough
444 | } else {
445 | params = a1;
446 | data = a2;
447 | success = a3;
448 | break;
449 | }
450 | case 1:
451 | if (isFunction(a1)) success = a1;
452 | else if (hasBody) data = a1;
453 | else params = a1;
454 | break;
455 | case 0: break;
456 | default:
457 | throw $resourceMinErr('badargs',
458 | "Expected up to 4 arguments [params, data, success, error], got {0} arguments", arguments.length);
459 | }
460 |
461 | var isInstanceCall = data instanceof Resource;
462 | var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
463 | var httpConfig = {};
464 | var responseInterceptor = action.interceptor && action.interceptor.response || defaultResponseInterceptor;
465 | var responseErrorInterceptor = action.interceptor && action.interceptor.responseError || undefined;
466 |
467 | forEach(action, function(value, key) {
468 | if (key != 'params' && key != 'isArray' && key != 'interceptor') {
469 | httpConfig[key] = copy(value);
470 | }
471 | });
472 |
473 | httpConfig.data = data;
474 | route.setUrlParams(httpConfig, extend({}, extractParams(data, action.params || {}), params), action.url);
475 |
476 | var promise = $http(httpConfig).then(function(response) {
477 | var data = response.data,
478 | promise = value.$promise;
479 |
480 | if (data) {
481 | if ( angular.isArray(data) != !!action.isArray ) {
482 | throw $resourceMinErr('badcfg', 'Error in resource configuration. Expected response' +
483 | ' to contain an {0} but got an {1}',
484 | action.isArray?'array':'object', angular.isArray(data)?'array':'object');
485 | }
486 | if (action.isArray) {
487 | value.length = 0;
488 | forEach(data, function(item) {
489 | value.push(new Resource(item));
490 | });
491 | } else {
492 | copy(data, value);
493 | value.$promise = promise;
494 | }
495 | }
496 |
497 | value.$resolved = true;
498 |
499 | (success||noop)(value, response.headers);
500 |
501 | response.resource = value;
502 |
503 | return response;
504 | }, function(response) {
505 | value.$resolved = true;
506 |
507 | (error||noop)(response);
508 |
509 | return $q.reject(response);
510 | }).then(responseInterceptor, responseErrorInterceptor);
511 |
512 |
513 | if (!isInstanceCall) {
514 | // we are creating instance / collection
515 | // - set the initial promise
516 | // - return the instance / collection
517 | value.$promise = promise;
518 | value.$resolved = false;
519 |
520 | return value;
521 | }
522 |
523 | // instance call
524 | return promise;
525 | };
526 |
527 |
528 | Resource.prototype['$' + name] = function(params, success, error) {
529 | if (isFunction(params)) {
530 | error = success; success = params; params = {};
531 | }
532 | var result = Resource[name](params, this, success, error);
533 | return result.$promise || result;
534 | };
535 | });
536 |
537 | Resource.bind = function(additionalParamDefaults){
538 | return ResourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
539 | };
540 |
541 | return Resource;
542 | }
543 |
544 | return ResourceFactory;
545 | }]);
546 |
547 |
548 | })(window, window.angular);
549 |
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/js/lib/angular-route-1.2.0rc1.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @license AngularJS v1.2.0rc1
3 | * (c) 2010-2012 Google, Inc. http://angularjs.org
4 | * License: MIT
5 | */
6 | (function(window, angular, undefined) {'use strict';
7 |
8 | var copy = angular.copy,
9 | equals = angular.equals,
10 | extend = angular.extend,
11 | forEach = angular.forEach,
12 | isDefined = angular.isDefined,
13 | isFunction = angular.isFunction,
14 | isString = angular.isString,
15 | jqLite = angular.element,
16 | noop = angular.noop,
17 | toJson = angular.toJson;
18 |
19 |
20 | function inherit(parent, extra) {
21 | return extend(new (extend(function() {}, {prototype:parent}))(), extra);
22 | }
23 |
24 | /**
25 | * @ngdoc overview
26 | * @name ngRoute
27 | * @description
28 | *
29 | * Module that provides routing and deeplinking services and directives for angular apps.
30 | */
31 |
32 | var ngRouteModule = angular.module('ngRoute', ['ng']).
33 | provider('$route', $RouteProvider);
34 |
35 | /**
36 | * @ngdoc object
37 | * @name ngRoute.$routeProvider
38 | * @function
39 | *
40 | * @description
41 | *
42 | * Used for configuring routes. See {@link ngRoute.$route $route} for an example.
43 | */
44 | function $RouteProvider(){
45 | var routes = {};
46 |
47 | /**
48 | * @ngdoc method
49 | * @name ngRoute.$routeProvider#when
50 | * @methodOf ngRoute.$routeProvider
51 | *
52 | * @param {string} path Route path (matched against `$location.path`). If `$location.path`
53 | * contains redundant trailing slash or is missing one, the route will still match and the
54 | * `$location.path` will be updated to add or drop the trailing slash to exactly match the
55 | * route definition.
56 | *
57 | * * `path` can contain named groups starting with a colon (`:name`). All characters up
58 | * to the next slash are matched and stored in `$routeParams` under the given `name`
59 | * when the route matches.
60 | * * `path` can contain named groups starting with a colon and ending with a star (`:name*`).
61 | * All characters are eagerly stored in `$routeParams` under the given `name`
62 | * when the route matches.
63 | * * `path` can contain optional named groups with a question mark (`:name?`).
64 | *
65 | * For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
66 | * `/color/brown/largecode/code/with/slashs/edit` and extract:
67 | *
68 | * * `color: brown`
69 | * * `largecode: code/with/slashs`.
70 | *
71 | *
72 | * @param {Object} route Mapping information to be assigned to `$route.current` on route
73 | * match.
74 | *
75 | * Object properties:
76 | *
77 | * - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly
78 | * created scope or the name of a {@link angular.Module#controller registered controller}
79 | * if passed as a string.
80 | * - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
81 | * published to scope under the `controllerAs` name.
82 | * - `template` – `{string=|function()=}` – html template as a string or a function that
83 | * returns an html template as a string which should be used by {@link
84 | * ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
85 | * This property takes precedence over `templateUrl`.
86 | *
87 | * If `template` is a function, it will be called with the following parameters:
88 | *
89 | * - `{Array.}` - route parameters extracted from the current
90 | * `$location.path()` by applying the current route
91 | *
92 | * - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
93 | * template that should be used by {@link ngRoute.directive:ngView ngView}.
94 | *
95 | * If `templateUrl` is a function, it will be called with the following parameters:
96 | *
97 | * - `{Array.}` - route parameters extracted from the current
98 | * `$location.path()` by applying the current route
99 | *
100 | * - `resolve` - `{Object.=}` - An optional map of dependencies which should
101 | * be injected into the controller. If any of these dependencies are promises, they will be
102 | * resolved and converted to a value before the controller is instantiated and the
103 | * `$routeChangeSuccess` event is fired. The map object is:
104 | *
105 | * - `key` – `{string}`: a name of a dependency to be injected into the controller.
106 | * - `factory` - `{string|function}`: If `string` then it is an alias for a service.
107 | * Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected}
108 | * and the return value is treated as the dependency. If the result is a promise, it is resolved
109 | * before its value is injected into the controller. Be aware that `ngRoute.$routeParams` will
110 | * still refer to the previous route within these resolve functions. Use `$route.current.params`
111 | * to access the new route parameters, instead.
112 | *
113 | * - `redirectTo` – {(string|function())=} – value to update
114 | * {@link ng.$location $location} path with and trigger route redirection.
115 | *
116 | * If `redirectTo` is a function, it will be called with the following parameters:
117 | *
118 | * - `{Object.}` - route parameters extracted from the current
119 | * `$location.path()` by applying the current route templateUrl.
120 | * - `{string}` - current `$location.path()`
121 | * - `{Object}` - current `$location.search()`
122 | *
123 | * The custom `redirectTo` function is expected to return a string which will be used
124 | * to update `$location.path()` and `$location.search()`.
125 | *
126 | * - `[reloadOnSearch=true]` - {boolean=} - reload route when only $location.search()
127 | * changes.
128 | *
129 | * If the option is set to `false` and url in the browser changes, then
130 | * `$routeUpdate` event is broadcasted on the root scope.
131 | *
132 | * - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
133 | *
134 | * If the option is set to `true`, then the particular route can be matched without being
135 | * case sensitive
136 | *
137 | * @returns {Object} self
138 | *
139 | * @description
140 | * Adds a new route definition to the `$route` service.
141 | */
142 | this.when = function(path, route) {
143 | routes[path] = extend(
144 | {reloadOnSearch: true},
145 | route,
146 | path && pathRegExp(path, route)
147 | );
148 |
149 | // create redirection for trailing slashes
150 | if (path) {
151 | var redirectPath = (path[path.length-1] == '/')
152 | ? path.substr(0, path.length-1)
153 | : path +'/';
154 |
155 | routes[redirectPath] = extend(
156 | {redirectTo: path},
157 | pathRegExp(redirectPath, route)
158 | );
159 | }
160 |
161 | return this;
162 | };
163 |
164 | /**
165 | * @param path {string} path
166 | * @param opts {Object} options
167 | * @return {?Object}
168 | *
169 | * @description
170 | * Normalizes the given path, returning a regular expression
171 | * and the original path.
172 | *
173 | * Inspired by pathRexp in visionmedia/express/lib/utils.js.
174 | */
175 | function pathRegExp(path, opts) {
176 | var insensitive = opts.caseInsensitiveMatch,
177 | ret = {
178 | originalPath: path,
179 | regexp: path
180 | },
181 | keys = ret.keys = [];
182 |
183 | path = path
184 | .replace(/([().])/g, '\\$1')
185 | .replace(/(\/)?:(\w+)([\?|\*])?/g, function(_, slash, key, option){
186 | var optional = option === '?' ? option : null;
187 | var star = option === '*' ? option : null;
188 | keys.push({ name: key, optional: !!optional });
189 | slash = slash || '';
190 | return ''
191 | + (optional ? '' : slash)
192 | + '(?:'
193 | + (optional ? slash : '')
194 | + (star && '(.+)?' || '([^/]+)?') + ')'
195 | + (optional || '');
196 | })
197 | .replace(/([\/$\*])/g, '\\$1');
198 |
199 | ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
200 | return ret;
201 | }
202 |
203 | /**
204 | * @ngdoc method
205 | * @name ngRoute.$routeProvider#otherwise
206 | * @methodOf ngRoute.$routeProvider
207 | *
208 | * @description
209 | * Sets route definition that will be used on route change when no other route definition
210 | * is matched.
211 | *
212 | * @param {Object} params Mapping information to be assigned to `$route.current`.
213 | * @returns {Object} self
214 | */
215 | this.otherwise = function(params) {
216 | this.when(null, params);
217 | return this;
218 | };
219 |
220 |
221 | this.$get = ['$rootScope', '$location', '$routeParams', '$q', '$injector', '$http', '$templateCache', '$sce',
222 | function( $rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) {
223 |
224 | /**
225 | * @ngdoc object
226 | * @name ngRoute.$route
227 | * @requires $location
228 | * @requires $routeParams
229 | *
230 | * @property {Object} current Reference to the current route definition.
231 | * The route definition contains:
232 | *
233 | * - `controller`: The controller constructor as define in route definition.
234 | * - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
235 | * controller instantiation. The `locals` contain
236 | * the resolved values of the `resolve` map. Additionally the `locals` also contain:
237 | *
238 | * - `$scope` - The current route scope.
239 | * - `$template` - The current route template HTML.
240 | *
241 | * @property {Array.} routes Array of all configured routes.
242 | *
243 | * @description
244 | * Is used for deep-linking URLs to controllers and views (HTML partials).
245 | * It watches `$location.url()` and tries to map the path to an existing route definition.
246 | *
247 | * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API.
248 | *
249 | * The `$route` service is typically used in conjunction with {@link ngRoute.directive:ngView ngView}
250 | * directive and the {@link ngRoute.$routeParams $routeParams} service.
251 | *
252 | * @example
253 | This example shows how changing the URL hash causes the `$route` to match a route against the
254 | URL, and the `ngView` pulls in the partial.
255 |
256 | Note that this example is using {@link ng.directive:script inlined templates}
257 | to get it working on jsfiddle as well.
258 |
259 |
260 |
261 |
262 | Choose:
263 |
Moby |
264 |
Moby: Ch1 |
265 |
Gatsby |
266 |
Gatsby: Ch4 |
267 |
Scarlet Letter
268 |
269 |
270 |
271 |
272 |
$location.path() = {{$location.path()}}
273 |
$route.current.templateUrl = {{$route.current.templateUrl}}
274 |
$route.current.params = {{$route.current.params}}
275 |
$route.current.scope.name = {{$route.current.scope.name}}
276 |
$routeParams = {{$routeParams}}
277 |
278 |
279 |
280 |
281 | controller: {{name}}
282 | Book Id: {{params.bookId}}
283 |
284 |
285 |
286 | controller: {{name}}
287 | Book Id: {{params.bookId}}
288 | Chapter Id: {{params.chapterId}}
289 |
290 |
291 |
292 | angular.module('ngView', ['ngRoute']).config(function($routeProvider, $locationProvider) {
293 | $routeProvider.when('/Book/:bookId', {
294 | templateUrl: 'book.html',
295 | controller: BookCntl,
296 | resolve: {
297 | // I will cause a 1 second delay
298 | delay: function($q, $timeout) {
299 | var delay = $q.defer();
300 | $timeout(delay.resolve, 1000);
301 | return delay.promise;
302 | }
303 | }
304 | });
305 | $routeProvider.when('/Book/:bookId/ch/:chapterId', {
306 | templateUrl: 'chapter.html',
307 | controller: ChapterCntl
308 | });
309 |
310 | // configure html5 to get links working on jsfiddle
311 | $locationProvider.html5Mode(true);
312 | });
313 |
314 | function MainCntl($scope, $route, $routeParams, $location) {
315 | $scope.$route = $route;
316 | $scope.$location = $location;
317 | $scope.$routeParams = $routeParams;
318 | }
319 |
320 | function BookCntl($scope, $routeParams) {
321 | $scope.name = "BookCntl";
322 | $scope.params = $routeParams;
323 | }
324 |
325 | function ChapterCntl($scope, $routeParams) {
326 | $scope.name = "ChapterCntl";
327 | $scope.params = $routeParams;
328 | }
329 |
330 |
331 |
332 | it('should load and compile correct template', function() {
333 | element('a:contains("Moby: Ch1")').click();
334 | var content = element('.doc-example-live [ng-view]').text();
335 | expect(content).toMatch(/controller\: ChapterCntl/);
336 | expect(content).toMatch(/Book Id\: Moby/);
337 | expect(content).toMatch(/Chapter Id\: 1/);
338 |
339 | element('a:contains("Scarlet")').click();
340 | sleep(2); // promises are not part of scenario waiting
341 | content = element('.doc-example-live [ng-view]').text();
342 | expect(content).toMatch(/controller\: BookCntl/);
343 | expect(content).toMatch(/Book Id\: Scarlet/);
344 | });
345 |
346 |
347 | */
348 |
349 | /**
350 | * @ngdoc event
351 | * @name ngRoute.$route#$routeChangeStart
352 | * @eventOf ngRoute.$route
353 | * @eventType broadcast on root scope
354 | * @description
355 | * Broadcasted before a route change. At this point the route services starts
356 | * resolving all of the dependencies needed for the route change to occurs.
357 | * Typically this involves fetching the view template as well as any dependencies
358 | * defined in `resolve` route property. Once all of the dependencies are resolved
359 | * `$routeChangeSuccess` is fired.
360 | *
361 | * @param {Route} next Future route information.
362 | * @param {Route} current Current route information.
363 | */
364 |
365 | /**
366 | * @ngdoc event
367 | * @name ngRoute.$route#$routeChangeSuccess
368 | * @eventOf ngRoute.$route
369 | * @eventType broadcast on root scope
370 | * @description
371 | * Broadcasted after a route dependencies are resolved.
372 | * {@link ngRoute.directive:ngView ngView} listens for the directive
373 | * to instantiate the controller and render the view.
374 | *
375 | * @param {Object} angularEvent Synthetic event object.
376 | * @param {Route} current Current route information.
377 | * @param {Route|Undefined} previous Previous route information, or undefined if current is first route entered.
378 | */
379 |
380 | /**
381 | * @ngdoc event
382 | * @name ngRoute.$route#$routeChangeError
383 | * @eventOf ngRoute.$route
384 | * @eventType broadcast on root scope
385 | * @description
386 | * Broadcasted if any of the resolve promises are rejected.
387 | *
388 | * @param {Route} current Current route information.
389 | * @param {Route} previous Previous route information.
390 | * @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
391 | */
392 |
393 | /**
394 | * @ngdoc event
395 | * @name ngRoute.$route#$routeUpdate
396 | * @eventOf ngRoute.$route
397 | * @eventType broadcast on root scope
398 | * @description
399 | *
400 | * The `reloadOnSearch` property has been set to false, and we are reusing the same
401 | * instance of the Controller.
402 | */
403 |
404 | var forceReload = false,
405 | $route = {
406 | routes: routes,
407 |
408 | /**
409 | * @ngdoc method
410 | * @name ngRoute.$route#reload
411 | * @methodOf ngRoute.$route
412 | *
413 | * @description
414 | * Causes `$route` service to reload the current route even if
415 | * {@link ng.$location $location} hasn't changed.
416 | *
417 | * As a result of that, {@link ngRoute.directive:ngView ngView}
418 | * creates new scope, reinstantiates the controller.
419 | */
420 | reload: function() {
421 | forceReload = true;
422 | $rootScope.$evalAsync(updateRoute);
423 | }
424 | };
425 |
426 | $rootScope.$on('$locationChangeSuccess', updateRoute);
427 |
428 | return $route;
429 |
430 | /////////////////////////////////////////////////////
431 |
432 | /**
433 | * @param on {string} current url
434 | * @param route {Object} route regexp to match the url against
435 | * @return {?Object}
436 | *
437 | * @description
438 | * Check if the route matches the current url.
439 | *
440 | * Inspired by match in
441 | * visionmedia/express/lib/router/router.js.
442 | */
443 | function switchRouteMatcher(on, route) {
444 | var keys = route.keys,
445 | params = {};
446 |
447 | if (!route.regexp) return null;
448 |
449 | var m = route.regexp.exec(on);
450 | if (!m) return null;
451 |
452 | var N = 0;
453 | for (var i = 1, len = m.length; i < len; ++i) {
454 | var key = keys[i - 1];
455 |
456 | var val = 'string' == typeof m[i]
457 | ? decodeURIComponent(m[i])
458 | : m[i];
459 |
460 | if (key && val) {
461 | params[key.name] = val;
462 | }
463 | }
464 | return params;
465 | }
466 |
467 | function updateRoute() {
468 | var next = parseRoute(),
469 | last = $route.current;
470 |
471 | if (next && last && next.$$route === last.$$route
472 | && equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) {
473 | last.params = next.params;
474 | copy(last.params, $routeParams);
475 | $rootScope.$broadcast('$routeUpdate', last);
476 | } else if (next || last) {
477 | forceReload = false;
478 | $rootScope.$broadcast('$routeChangeStart', next, last);
479 | $route.current = next;
480 | if (next) {
481 | if (next.redirectTo) {
482 | if (isString(next.redirectTo)) {
483 | $location.path(interpolate(next.redirectTo, next.params)).search(next.params)
484 | .replace();
485 | } else {
486 | $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
487 | .replace();
488 | }
489 | }
490 | }
491 |
492 | $q.when(next).
493 | then(function() {
494 | if (next) {
495 | var locals = extend({}, next.resolve),
496 | template, templateUrl;
497 |
498 | forEach(locals, function(value, key) {
499 | locals[key] = isString(value) ? $injector.get(value) : $injector.invoke(value);
500 | });
501 |
502 | if (isDefined(template = next.template)) {
503 | if (isFunction(template)) {
504 | template = template(next.params);
505 | }
506 | } else if (isDefined(templateUrl = next.templateUrl)) {
507 | if (isFunction(templateUrl)) {
508 | templateUrl = templateUrl(next.params);
509 | }
510 | templateUrl = $sce.getTrustedResourceUrl(templateUrl);
511 | if (isDefined(templateUrl)) {
512 | next.loadedTemplateUrl = templateUrl;
513 | template = $http.get(templateUrl, {cache: $templateCache}).
514 | then(function(response) { return response.data; });
515 | }
516 | }
517 | if (isDefined(template)) {
518 | locals['$template'] = template;
519 | }
520 | return $q.all(locals);
521 | }
522 | }).
523 | // after route change
524 | then(function(locals) {
525 | if (next == $route.current) {
526 | if (next) {
527 | next.locals = locals;
528 | copy(next.params, $routeParams);
529 | }
530 | $rootScope.$broadcast('$routeChangeSuccess', next, last);
531 | }
532 | }, function(error) {
533 | if (next == $route.current) {
534 | $rootScope.$broadcast('$routeChangeError', next, last, error);
535 | }
536 | });
537 | }
538 | }
539 |
540 |
541 | /**
542 | * @returns the current active route, by matching it against the URL
543 | */
544 | function parseRoute() {
545 | // Match a route
546 | var params, match;
547 | forEach(routes, function(route, path) {
548 | if (!match && (params = switchRouteMatcher($location.path(), route))) {
549 | match = inherit(route, {
550 | params: extend({}, $location.search(), params),
551 | pathParams: params});
552 | match.$$route = route;
553 | }
554 | });
555 | // No route matched; fallback to "otherwise" route
556 | return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
557 | }
558 |
559 | /**
560 | * @returns interpolation of the redirect path with the parameters
561 | */
562 | function interpolate(string, params) {
563 | var result = [];
564 | forEach((string||'').split(':'), function(segment, i) {
565 | if (i == 0) {
566 | result.push(segment);
567 | } else {
568 | var segmentMatch = segment.match(/(\w+)(.*)/);
569 | var key = segmentMatch[1];
570 | result.push(params[key]);
571 | result.push(segmentMatch[2] || '');
572 | delete params[key];
573 | }
574 | });
575 | return result.join('');
576 | }
577 | }];
578 | }
579 |
580 | ngRouteModule.provider('$routeParams', $RouteParamsProvider);
581 |
582 |
583 | /**
584 | * @ngdoc object
585 | * @name ngRoute.$routeParams
586 | * @requires $route
587 | *
588 | * @description
589 | * Current set of route parameters. The route parameters are a combination of the
590 | * {@link ng.$location $location} `search()`, and `path()`. The `path` parameters
591 | * are extracted when the {@link ngRoute.$route $route} path is matched.
592 | *
593 | * In case of parameter name collision, `path` params take precedence over `search` params.
594 | *
595 | * The service guarantees that the identity of the `$routeParams` object will remain unchanged
596 | * (but its properties will likely change) even when a route change occurs.
597 | *
598 | * Note that the `$routeParams` are only updated *after* a route change completes successfully.
599 | * This means that you cannot rely on `$routeParams` being correct in route resolve functions.
600 | * Instead you can use `$route.current.params` to access the new route's parameters.
601 | *
602 | * @example
603 | *
604 | * // Given:
605 | * // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
606 | * // Route: /Chapter/:chapterId/Section/:sectionId
607 | * //
608 | * // Then
609 | * $routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
610 | *
611 | */
612 | function $RouteParamsProvider() {
613 | this.$get = function() { return {}; };
614 | }
615 |
616 | /**
617 | * @ngdoc directive
618 | * @name ngRoute.directive:ngView
619 | * @restrict ECA
620 | *
621 | * @description
622 | * # Overview
623 | * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
624 | * including the rendered template of the current route into the main layout (`index.html`) file.
625 | * Every time the current route changes, the included view changes with it according to the
626 | * configuration of the `$route` service.
627 | *
628 | * @animations
629 | * enter - animation is used to bring new content into the browser.
630 | * leave - animation is used to animate existing content away.
631 | *
632 | * The enter and leave animation occur concurrently.
633 | *
634 | * @scope
635 | * @example
636 |
637 |
638 |
639 | Choose:
640 |
Moby |
641 |
Moby: Ch1 |
642 |
Gatsby |
643 |
Gatsby: Ch4 |
644 |
Scarlet Letter
645 |
646 |
649 |
650 |
651 |
$location.path() = {{main.$location.path()}}
652 |
$route.current.templateUrl = {{main.$route.current.templateUrl}}
653 |
$route.current.params = {{main.$route.current.params}}
654 |
$route.current.scope.name = {{main.$route.current.scope.name}}
655 |
$routeParams = {{main.$routeParams}}
656 |
657 |
658 |
659 |
660 |
661 | controller: {{book.name}}
662 | Book Id: {{book.params.bookId}}
663 |
664 |
665 |
666 |
667 |
668 | controller: {{chapter.name}}
669 | Book Id: {{chapter.params.bookId}}
670 | Chapter Id: {{chapter.params.chapterId}}
671 |
672 |
673 |
674 |
675 | .example-animate-container {
676 | position:relative;
677 | background:white;
678 | border:1px solid black;
679 | height:40px;
680 | overflow:hidden;
681 | }
682 |
683 | .example-animate-container > div {
684 | padding:10px;
685 | }
686 |
687 | .view-example.ng-enter, .view-example.ng-leave {
688 | -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
689 | -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
690 | -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
691 | transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
692 |
693 | display:block;
694 | width:100%;
695 | border-left:1px solid black;
696 |
697 | position:absolute;
698 | top:0;
699 | left:0;
700 | right:0;
701 | bottom:0;
702 | padding:10px;
703 | }
704 |
705 | .example-animate-container {
706 | position:relative;
707 | height:100px;
708 | }
709 |
710 | .view-example.ng-enter {
711 | left:100%;
712 | }
713 | .view-example.ng-enter.ng-enter-active {
714 | left:0;
715 | }
716 |
717 | .view-example.ng-leave { }
718 | .view-example.ng-leave.ng-leave-active {
719 | left:-100%;
720 | }
721 |
722 |
723 |
724 | angular.module('ngViewExample', ['ngRoute', 'ngAnimate'], function($routeProvider, $locationProvider) {
725 | $routeProvider.when('/Book/:bookId', {
726 | templateUrl: 'book.html',
727 | controller: BookCntl,
728 | controllerAs: 'book'
729 | });
730 | $routeProvider.when('/Book/:bookId/ch/:chapterId', {
731 | templateUrl: 'chapter.html',
732 | controller: ChapterCntl,
733 | controllerAs: 'chapter'
734 | });
735 |
736 | // configure html5 to get links working on jsfiddle
737 | $locationProvider.html5Mode(true);
738 | });
739 |
740 | function MainCntl($route, $routeParams, $location) {
741 | this.$route = $route;
742 | this.$location = $location;
743 | this.$routeParams = $routeParams;
744 | }
745 |
746 | function BookCntl($routeParams) {
747 | this.name = "BookCntl";
748 | this.params = $routeParams;
749 | }
750 |
751 | function ChapterCntl($routeParams) {
752 | this.name = "ChapterCntl";
753 | this.params = $routeParams;
754 | }
755 |
756 |
757 |
758 | it('should load and compile correct template', function() {
759 | element('a:contains("Moby: Ch1")').click();
760 | var content = element('.doc-example-live [ng-view]').text();
761 | expect(content).toMatch(/controller\: ChapterCntl/);
762 | expect(content).toMatch(/Book Id\: Moby/);
763 | expect(content).toMatch(/Chapter Id\: 1/);
764 |
765 | element('a:contains("Scarlet")').click();
766 | content = element('.doc-example-live [ng-view]').text();
767 | expect(content).toMatch(/controller\: BookCntl/);
768 | expect(content).toMatch(/Book Id\: Scarlet/);
769 | });
770 |
771 |
772 | */
773 |
774 |
775 | /**
776 | * @ngdoc event
777 | * @name ngRoute.directive:ngView#$viewContentLoaded
778 | * @eventOf ngRoute.directive:ngView
779 | * @eventType emit on the current ngView scope
780 | * @description
781 | * Emitted every time the ngView content is reloaded.
782 | */
783 | var NG_VIEW_PRIORITY = 500;
784 | var ngViewDirective = ['$route', '$anchorScroll', '$compile', '$controller', '$animate',
785 | function($route, $anchorScroll, $compile, $controller, $animate) {
786 | return {
787 | restrict: 'ECA',
788 | terminal: true,
789 | priority: NG_VIEW_PRIORITY,
790 | compile: function(element, attr) {
791 | var onloadExp = attr.onload || '';
792 |
793 | element.html('');
794 | var anchor = jqLite(document.createComment(' ngView '));
795 | element.replaceWith(anchor);
796 |
797 | return function(scope) {
798 | var currentScope, currentElement;
799 |
800 | scope.$on('$routeChangeSuccess', update);
801 | update();
802 |
803 | function cleanupLastView() {
804 | if (currentScope) {
805 | currentScope.$destroy();
806 | currentScope = null;
807 | }
808 | if(currentElement) {
809 | $animate.leave(currentElement);
810 | currentElement = null;
811 | }
812 | }
813 |
814 | function update() {
815 | var locals = $route.current && $route.current.locals,
816 | template = locals && locals.$template;
817 |
818 | if (template) {
819 | cleanupLastView();
820 |
821 | currentScope = scope.$new();
822 | currentElement = element.clone();
823 | currentElement.html(template);
824 | $animate.enter(currentElement, null, anchor);
825 |
826 | var link = $compile(currentElement, false, NG_VIEW_PRIORITY - 1),
827 | current = $route.current;
828 |
829 | if (current.controller) {
830 | locals.$scope = currentScope;
831 | var controller = $controller(current.controller, locals);
832 | if (current.controllerAs) {
833 | currentScope[current.controllerAs] = controller;
834 | }
835 | currentElement.data('$ngControllerController', controller);
836 | currentElement.children().data('$ngControllerController', controller);
837 | }
838 |
839 | current.scope = currentScope;
840 |
841 | link(currentScope);
842 |
843 | currentScope.$emit('$viewContentLoaded');
844 | currentScope.$eval(onloadExp);
845 |
846 | // $anchorScroll might listen on event...
847 | $anchorScroll();
848 | } else {
849 | cleanupLastView();
850 | }
851 | }
852 | }
853 | }
854 | };
855 | }];
856 |
857 | ngRouteModule.directive('ngView', ngViewDirective);
858 |
859 |
860 | })(window, window.angular);
861 |
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/js/menu.js:
--------------------------------------------------------------------------------
1 | var sidebarMenu = angular.module('sidebarMenu', ['ngRoute'])
2 | .config(function ($locationProvider, $routeProvider) {
3 | // browser reload doesn't work when html5 mode is turned on..
4 | //$locationProvider.html5Mode(true);
5 | $routeProvider
6 | .when('/', {templateUrl: '/partials/hello.html'})
7 | .when('/sharing-data', {templateUrl: '/partials/sharing-data.html'})
8 | .when('/filters-and-directives', {templateUrl: '/partials/filters-and-directives.html'})
9 | .when('/controller-and-directives', {templateUrl: '/partials/controller-and-directives.html'})
10 | .when('/scope-isolation', {templateUrl: '/partials/scope-isolation.html'})
11 | .when('/raffler', {templateUrl: '/partials/raffler.html'})
12 | .when('/tabs', {templateUrl: '/partials/tabs.html'})
13 | .when('/persons', {templateUrl: '/partials/persons.html'})
14 | .otherwise({redirectTo: '/'})
15 | });
16 |
17 | sidebarMenu.controller("MenuCtrl", function ($scope, $location, Menu) {
18 | $scope.menu = Menu;
19 |
20 | /*
21 | See: http://stackoverflow.com/questions/12592472/how-to-highlight-a-current-menu-item-in-angularjs
22 | */
23 | $scope.getClass = function (item) {
24 | //console.log("location.path=" + $location.path())
25 | //console.log("item.href=" + item.href)
26 | //if ($location.path() == item.href) {
27 | if ($location.path() == item.href.substr(2)) {
28 | return "active"
29 | } else {
30 | return ""
31 | }
32 | }
33 | });
34 |
35 | sidebarMenu.directive("menu", function () {
36 | return {
37 | restrict: "A",
38 | template: ''
42 | }
43 | });
44 |
45 | sidebarMenu.factory('Menu', function () {
46 | var Menu = {};
47 | Menu.items = [
48 | {
49 | class: "",
50 | href: "/#!/index.html",
51 | //href: "/index.html",
52 | name: "Hello world"
53 | },
54 | {
55 | class: "",
56 | href: "/#/sharing-data",
57 | //href: "/sharing-data",
58 | name: "Sharing data"
59 | },
60 | {
61 | class: "",
62 | href: "/#/filters-and-directives",
63 | //href: "/filters-and-directives",
64 | name: "Filters & directives"
65 | },
66 | {
67 | class: "",
68 | href: "/#/controller-and-directives",
69 | //href: "/controller-and-directives",
70 | name: "Controller & directives"
71 | },
72 | {
73 | class: "",
74 | href: "/#/scope-isolation",
75 | //href: "/scope-isolation",
76 | name: "Scope isolation"
77 | },
78 | {
79 | class: "",
80 | href: "/#/raffler",
81 | //href: "/raffler",
82 | name: "Raffle example"
83 | },
84 | {
85 | class: "",
86 | href: "/#/tabs",
87 | //href: "/tabs",
88 | name: "Tabs"
89 | },
90 | {
91 | class: "",
92 | href: "/#/persons",
93 | //href: "/persons",
94 | name: "Person Admin"
95 | }
96 | ];
97 | return Menu;
98 | });
99 |
100 |
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/js/persons.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Author: Per Spilling, per@kodemaker.no
3 | */
4 | var myApp = angular.module('persons', ['ngResource', 'ui.bootstrap'], function ($dialogProvider) {
5 | $dialogProvider.options({backdropClick: false, dialogFade: true});
6 | });
7 |
8 | /**
9 | * Configure the PersonsResource. In order to solve the Single Origin Policy issue in the browser
10 | * I have set up a Jetty proxy servlet to forward requests transparently to the API server.
11 | * See the web.xml file for details on that.
12 | */
13 | myApp.factory('PersonsResource', function ($resource) {
14 | return $resource('/api/persons', {}, {});
15 | });
16 |
17 | myApp.factory('PersonResource', function ($resource) {
18 | return $resource('/api/persons/:id', {}, {});
19 | });
20 |
21 | function PersonsCtrl($scope, PersonsResource, PersonResource, $dialog, $q) {
22 | /**
23 | * Define an object that will hold data for the form. The persons list will be pre-loaded with the list of
24 | * persons from the server. The personForm.person object is bound to the person form in the HTML via the
25 | * ng-model directive.
26 | */
27 | $scope.personForm = {
28 | show: true,
29 | person: {}
30 | }
31 | $scope.persons = PersonsResource.query();
32 |
33 | /**
34 | * Function used to toggle the show variable between true and false, which in turn determines if the person form
35 | * should be displayed of not.
36 | */
37 | $scope.togglePersonForm = function () {
38 | $scope.personForm.show = !$scope.personForm.show;
39 | }
40 |
41 | /**
42 | * Clear the person data from the form.
43 | */
44 | $scope.clearForm = function () {
45 | $scope.personForm.person = {}
46 | }
47 |
48 | /**
49 | * Save a person. Make sure that a person object is present before calling the service.
50 | */
51 | $scope.savePerson = function (person) {
52 | if (person != undefined) {
53 | /**
54 | * Here we need to ensure that the PersonsResource.query() is done after the PersonsResource.save. This
55 | * is achieved by using the $promise returned by the $resource object.
56 | */
57 | PersonsResource.save(person).$promise.then(function() {
58 | $scope.persons = PersonsResource.query();
59 | $scope.personForm.person = {} // clear the form
60 | });
61 | }
62 | }
63 |
64 | /**
65 | * Set the person to be edited in the person form.
66 | */
67 | $scope.editPerson = function (p) {
68 | $scope.personForm.person = p
69 | }
70 |
71 | /**
72 | * Delete a person. Present a modal dialog box to the user to make the user confirm that the person item really
73 | * should be deleted.
74 | */
75 | $scope.deletePerson = function (person) {
76 | var msgBox = $dialog.messageBox('You are about to delete a person from the database', 'This cannot be undone. Are you sure?', [
77 | {label: 'Yes', result: 'yes'},
78 | {label: 'Cancel', result: 'no'}
79 | ])
80 | msgBox.open().then(function (result) {
81 | if (result === 'yes') {
82 | // remove from the server and reload the person list from the server after the delete
83 | PersonResource.delete({id: person.id}).$promise.then(function() {
84 | $scope.persons = PersonsResource.query();
85 | });
86 | }
87 | });
88 | }
89 | }
90 |
91 | /*
92 | $scope.kodemakerPersons = {}
93 | $scope.persons = PersonsResource.query(function (response) {
94 | angular.forEach(response, function (person) {
95 | console.log('person.name=' + person.name)
96 | });
97 | });
98 | */
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/js/raffler.js:
--------------------------------------------------------------------------------
1 | var app = angular.module('raffleApp', []);
2 |
3 | app.controller("RaffleCtrl", function ($scope) {
4 | $scope.entries = [
5 | {name: "Larry"},
6 | {name: "Curly"},
7 | {name: "Barry"}
8 | ]
9 |
10 | // 2 versions of the addEntry() function; one without params and one with.
11 | /*
12 | $scope.addEntry = function () {
13 | $scope.entries.push($scope.newEntry)
14 | $scope.newEntry = {}
15 | }
16 | */
17 |
18 | $scope.addEntry = function (newEntry) {
19 | $scope.entries.push(newEntry);
20 | $scope.newEntry = {}
21 | }
22 |
23 | $scope.drawWinner = function () {
24 | entry = $scope.entries[Math.floor(Math.random() * $scope.entries.length)]
25 | entry.winner = true
26 | $scope.lastWinner = entry
27 | }
28 | });
29 |
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/js/scope-isolation.js:
--------------------------------------------------------------------------------
1 | var module = angular.module('scopeIsolation', []);
2 |
3 | module.controller("ChoreCtrl", function ($scope) {
4 | $scope.logChore = function (chore) {
5 | alert(chore + " is done!");
6 | };
7 | $scope.callHome = function (message) {
8 | alert(message)
9 | };
10 | $scope.ctrlFlavor = "blackberry";
11 | $scope.ctrlFruit = "apple"
12 | });
13 |
14 | module.directive("kid", function () {
15 | return {
16 | restrict: "E",
17 | scope: {
18 | done: "&"
19 | },
20 | template:
21 | '' +
22 | '
' +
23 | ' ' +
24 | 'I\'m done! ' +
25 | '{{chore}} ' +
26 | '
' +
27 | '
'
28 | }
29 | });
30 |
31 | module.directive("drink", function () {
32 | return {
33 | restrict: "E",
34 | scope: {
35 | flavor: "@"
36 | },
37 | template: 'flavor={{flavor}}
'
38 | }
39 | });
40 |
41 | module.directive("eat", function () {
42 | return {
43 | restrict: "E",
44 | scope: {
45 | fruit: "="
46 | },
47 | template: ' '
48 | }
49 | });
50 |
51 | module.directive("phone", function () {
52 | return {
53 | restrict: "E",
54 | scope: {
55 | dial: "&"
56 | },
57 | template:
58 | '' +
59 | '
' +
60 | ' ' +
61 | 'Call home! ' +
62 | '
' +
63 | '
'
64 | }
65 | });
66 |
67 |
68 |
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/js/sharing-data.js:
--------------------------------------------------------------------------------
1 | var sharingData = angular.module('sharingData', []);
2 |
3 | sharingData.factory('Data', function() {
4 | return {message: "I'm data from a service"}
5 | })
6 |
7 | // A filter function
8 | sharingData.filter('reverse', function () {
9 | return function (text) {
10 | return text.split("").reverse().join("");
11 | }
12 | })
13 |
14 | function SDFirstCtrl($scope, Data) {
15 | $scope.data = Data;
16 | }
17 |
18 | function SDSecondCtrl($scope, Data) {
19 | $scope.data = Data;
20 |
21 | $scope.reversedMessage = function (message) {
22 | return message.split("").reverse().join("");
23 | }
24 | }
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/js/tabset.js:
--------------------------------------------------------------------------------
1 | var myApp = angular.module('tabs',[]);
2 |
3 | function MyCtrl($scope) {
4 | $scope.date= new Date();
5 | }
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/js/todo.js:
--------------------------------------------------------------------------------
1 |
2 | function TodoCtrl($scope) {
3 | $scope.todos = [
4 | {text:'learn angular', done:true},
5 | {text:'build an angular app', done:false}];
6 |
7 | $scope.addTodo = function() {
8 | $scope.todos.push({text:$scope.todoText, done:false});
9 | $scope.todoText = '';
10 | };
11 |
12 | $scope.remaining = function() {
13 | var count = 0;
14 | angular.forEach($scope.todos, function(todo) {
15 | count += todo.done ? 0 : 1;
16 | });
17 | return count;
18 | };
19 |
20 | $scope.archive = function() {
21 | var oldTodos = $scope.todos;
22 | $scope.todos = [];
23 | angular.forEach(oldTodos, function(todo) {
24 | if (!todo.done) $scope.todos.push(todo);
25 | });
26 | };
27 | }
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/js/twitter.js:
--------------------------------------------------------------------------------
1 | var twitterApp = angular.module('twitterApp', []);
2 |
3 | twitterApp.controller("AppCtrl", function ($scope) {
4 | $scope.loadMoreTweets = function ($scope) {
5 | alert("Loading more tweets");
6 | }
7 |
8 | $scope.deleteTweets = function ($scope) {
9 | alert("Deleting tweets");
10 | }
11 | })
12 |
13 | /**
14 | * A directive with a behaviour function
15 | */
16 | twitterApp.directive("enter", function () {
17 | return function(scope, element, attrs) {
18 | element.bind("mouseenter", function () {
19 | scope.$apply(attrs.enter);
20 | })
21 | }
22 | })
23 |
24 | /**
25 | * A directive that will be reused by other directives
26 | */
27 | twitterApp.directive("superhero", function () {
28 | return {
29 | restrict: "E",
30 | scope: {},
31 |
32 | controller: function ($scope) {
33 | $scope.abilities = []
34 |
35 | this.addStrength = function () {
36 | $scope.abilities.push("strength")
37 | }
38 |
39 | this.addSpeed = function () {
40 | $scope.abilities.push("speed")
41 | }
42 |
43 | this.addFlight = function () {
44 | $scope.abilities.push("flight")
45 | }
46 | },
47 |
48 | link: function (scope, element) {
49 | element.addClass("btn"),
50 | element.bind("mouseenter", function () {
51 | console.log(scope.abilities)
52 | })
53 | }
54 | }
55 | })
56 |
57 | /**
58 | * A directive that uses (requires) the controller of another directive.
59 | */
60 | twitterApp.directive("strength", function () {
61 | return {
62 | require: "superhero",
63 | link: function (scope, element, attrs, ctrl) {
64 | ctrl.addStrength();
65 | }
66 | }
67 | })
68 |
69 | twitterApp.directive("speed", function () {
70 | return {
71 | require: "superhero",
72 | link: function (scope, element, attrs, ctrl) {
73 | ctrl.addSpeed();
74 | }
75 | }
76 | })
77 |
78 | twitterApp.directive("flight", function () {
79 | return {
80 | require: "superhero",
81 | link: function (scope, element, attrs, ctrl) {
82 | ctrl.addFlight();
83 | }
84 | }
85 | })
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/partials/controller-and-directives.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Roll over to load more tweets
5 |
Roll over to delete tweets
6 |
7 |
8 | Moving the mouse over the buttons will log a message to the console
9 |
Superman
10 |
The flash
11 |
12 |
13 |
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/partials/filters-and-directives.html:
--------------------------------------------------------------------------------
1 |
2 | Filter example
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {{actor.name}}
14 | {{actor.character}}
15 |
16 |
17 |
18 |
19 |
20 | Directive and behaviour examples
21 |
22 |
23 |
24 |
25 |
26 | This is the place
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/partials/hello.html:
--------------------------------------------------------------------------------
1 | AngularJS Hello, World!
2 |
3 |
4 |
5 |
Name provided by user:
6 |
7 |
8 |
Hello {{yourName}}!
9 | Angular can add too: {{ 1+2 }}.
10 |
11 |
12 |
Simple controller
13 |
14 |
15 | Name provided by the controller:
16 |
17 |
Hello {{data.message}}!
18 |
19 |
20 |
21 |
22 |
23 | This is a little example application that I have used to learn to use the AngularJS and Dropwizard
24 | frameworks. It also serves as a project template that can be used to get a new project up and running
25 | quickly using these frameworks + Jetty & Maven.
26 |
27 |
28 | The examples have largely been taken from www.egghead.io
29 | and the Raffle example from
30 | RailsCast (subscription need).
31 |
32 |
33 |
34 |
35 |
36 |
37 | Model scope used several places via the "dot"
38 |
39 |
40 | {{data.message2}}
41 |
42 |
43 |
44 |
45 |
{{data.message2}}
46 |
47 |
48 |
49 |
50 |
51 |
{{data.message2}}
52 |
53 |
54 |
80 |
81 |
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/partials/persons.html:
--------------------------------------------------------------------------------
1 | Simple CRUD app using RESTful backend services
2 |
3 |
4 | Note: For this example to run, make sure that the backend services in the dw-server
have been
5 | started. See the README file in that module for how to do that.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 | Show person form
18 | Hide person form
20 |
21 |
22 |
23 |
35 |
36 |
37 |
List of persons
38 |
39 |
40 |
41 |
42 | Operation
43 | Id
44 | Name
45 | Email
46 | Phone
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | {{p.id}}
56 | {{p.name}}
57 | {{p.email}}
58 | {{p.phone}}
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/partials/raffler.html:
--------------------------------------------------------------------------------
1 | Raffler
2 |
6 |
7 |
11 |
15 |
16 |
17 | {{entry.name}}
18 | WINNER
19 |
20 |
21 | entries.length={{entries.length}}
22 |
Draw Winner
23 |
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/partials/scope-isolation.html:
--------------------------------------------------------------------------------
1 |
2 |
Linking with '&' scope operator
3 |
abc
4 |
5 |
6 |
Linking with '@' scope operator
7 |
8 |
9 |
10 |
11 |
Linking with '=' scope operator
12 |
13 |
14 |
15 |
16 |
Linking again with '&' scope operator
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/partials/sharing-data.html:
--------------------------------------------------------------------------------
1 | Sharing data between controllers
2 |
3 |
4 |
5 |
{{data.message}}
6 |
7 |
8 |
9 |
10 |
Reversed message:
11 |
12 | {{reversedMessage(data.message)}}
13 |
14 | {{data.message|reverse}}
15 |
16 |
--------------------------------------------------------------------------------
/angularjs-webapp/src/main/webapp/partials/tabs.html:
--------------------------------------------------------------------------------
1 | Tabs example from http://angularjs.org/
2 |
3 |
4 |
5 | Date: {{ '2012-04-01' | date:'fullDate' }}
6 | Currency: {{ 123456 | currency }}
7 | Number: {{ 98765.4321 | number }}
8 |
9 |
10 |
15 |
16 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'base'
2 |
3 | allprojects {
4 | group = 'no.kodemaker.ps'
5 | version = '1.0-SNAPSHOT'
6 | }
7 |
8 | // Dependency mgmt.
9 | ext.dropwizard_version = '0.6.2'
10 | ext.jetty_version = '8.1.10.v20130312'
11 |
12 | ext.libs = [
13 | jetty_webapp: "org.eclipse.jetty:jetty-webapp:$jetty_version",
14 | jetty_servlets: "org.eclipse.jetty:jetty-servlets:$jetty_version",
15 | servlet_jsp: 'org.glassfish.web:javax.servlet.jsp:2.2.3',
16 | dropwizard_core: "com.yammer.dropwizard:dropwizard-core:$dropwizard_version",
17 | dropwizard_jdbi: "com.yammer.dropwizard:dropwizard-jdbi:$dropwizard_version",
18 | dropwizard_db: "com.yammer.dropwizard:dropwizard-db:$dropwizard_version",
19 | h2: 'com.h2database:h2:1.3.173',
20 | jersey_client: 'com.sun.jersey:jersey-client:1.12',
21 | junit: 'junit:junit:4.8.1'
22 | ]
23 |
24 | subprojects {
25 | apply plugin: 'maven'
26 | apply plugin: 'java'
27 | sourceCompatibility = 1.7
28 | targetCompatibility = 1.7
29 |
30 | repositories { mavenCentral() }
31 |
32 | dependencies { testCompile libs.junit }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/doc/deployment_diagram.graffle/data.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ApplicationVersion
6 |
7 | com.omnigroup.OmniGraffle.MacAppStore
8 | 139.18
9 |
10 | CreationDate
11 | 2013-08-08 13:11:24 +0000
12 | Creator
13 | Per Spilling
14 | GraphDocumentVersion
15 | 8
16 | GuidesLocked
17 | NO
18 | GuidesVisible
19 | YES
20 | ImageCounter
21 | 3
22 | ImageLinkBack
23 |
24 |
25 |
26 |
27 | ImageList
28 |
29 | image2.ai
30 | image1.ai
31 |
32 | LinksVisible
33 | NO
34 | MagnetsVisible
35 | NO
36 | MasterSheets
37 |
38 | ModificationDate
39 | 2013-08-21 21:02:14 +0000
40 | Modifier
41 | Per Spilling
42 | NotesVisible
43 | NO
44 | OriginVisible
45 | NO
46 | PageBreaks
47 | YES
48 | PrintInfo
49 |
50 | NSBottomMargin
51 |
52 | float
53 | 41
54 |
55 | NSHorizonalPagination
56 |
57 | coded
58 | BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
59 |
60 | NSLeftMargin
61 |
62 | float
63 | 18
64 |
65 | NSPaperSize
66 |
67 | size
68 | {595.28001499176025, 841.8900146484375}
69 |
70 | NSPrintReverseOrientation
71 |
72 | int
73 | 0
74 |
75 | NSRightMargin
76 |
77 | float
78 | 18
79 |
80 | NSTopMargin
81 |
82 | float
83 | 18
84 |
85 |
86 | ReadOnly
87 | NO
88 | Sheets
89 |
90 |
91 | ActiveLayerIndex
92 | 0
93 | AutoAdjust
94 |
95 | BackgroundGraphic
96 |
97 | Bounds
98 | {{0, 0}, {559.28001499176025, 782.8900146484375}}
99 | Class
100 | SolidGraphic
101 | ID
102 | 2
103 | Style
104 |
105 | shadow
106 |
107 | Draws
108 | NO
109 |
110 | stroke
111 |
112 | Draws
113 | NO
114 |
115 |
116 |
117 | BaseZoom
118 | 0
119 | CanvasOrigin
120 | {0, 0}
121 | ColumnAlign
122 | 1
123 | ColumnSpacing
124 | 36
125 | DisplayScale
126 | 1.000 cm = 1.000 cm
127 | GraphicsList
128 |
129 |
130 | Class
131 | LineGraphic
132 | Head
133 |
134 | ID
135 | 36
136 | Position
137 | 0.42412695288658142
138 |
139 | ID
140 | 39
141 | Points
142 |
143 | {360.50062033517474, 203.4115575908186}
144 | {337.5, 202.26475974917412}
145 |
146 | Style
147 |
148 | stroke
149 |
150 | HeadArrow
151 | 0
152 | Legacy
153 |
154 | LineType
155 | 1
156 | Pattern
157 | 1
158 | TailArrow
159 | 0
160 |
161 |
162 | Tail
163 |
164 | ID
165 | 15
166 |
167 |
168 |
169 | Class
170 | LineGraphic
171 | Head
172 |
173 | ID
174 | 31
175 |
176 | ID
177 | 36
178 | Points
179 |
180 | {337.5, 173}
181 | {337.50000095367432, 242}
182 |
183 | Style
184 |
185 | stroke
186 |
187 | HeadArrow
188 | FilledArrow
189 | Legacy
190 |
191 | LineType
192 | 1
193 | TailArrow
194 | 0
195 |
196 |
197 | Tail
198 |
199 | ID
200 | 30
201 |
202 |
203 |
204 | Bounds
205 | {{361, 187}, {163, 41}}
206 | Class
207 | ShapedGraphic
208 | ID
209 | 15
210 | Shape
211 | NoteShape
212 | Style
213 |
214 | fill
215 |
216 | Color
217 |
218 | b
219 | 0.4
220 | g
221 | 1
222 | r
223 | 0.8
224 |
225 |
226 |
227 | Text
228 |
229 | Text
230 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
231 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
232 | {\colortbl;\red255\green255\blue255;}
233 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
234 |
235 | \f0\fs24 \cf0 /api proxy to localhost:9000}
236 | VerticalPad
237 | 0
238 |
239 |
240 |
241 | Bounds
242 | {{137.5, 177}, {114, 14}}
243 | Class
244 | ShapedGraphic
245 | FitText
246 | YES
247 | Flow
248 | Resize
249 | FontInfo
250 |
251 | Font
252 | Helvetica
253 | Size
254 | 12
255 |
256 | ID
257 | 47
258 | Shape
259 | Rectangle
260 | Style
261 |
262 | fill
263 |
264 | Draws
265 | NO
266 |
267 | shadow
268 |
269 | Draws
270 | NO
271 |
272 | stroke
273 |
274 | Draws
275 | NO
276 |
277 |
278 | Text
279 |
280 | Pad
281 | 0
282 | Text
283 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
284 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
285 | {\colortbl;\red255\green255\blue255;}
286 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
287 |
288 | \f0\b\fs24 \cf0 Single Origin Policy}
289 | VerticalPad
290 | 0
291 |
292 | Wrap
293 | NO
294 |
295 |
296 | Bounds
297 | {{157, 190}, {74, 69}}
298 | Class
299 | ShapedGraphic
300 | ID
301 | 46
302 | ImageID
303 | 2
304 | Shape
305 | Rectangle
306 | Style
307 |
308 | fill
309 |
310 | Draws
311 | NO
312 |
313 | shadow
314 |
315 | Draws
316 | NO
317 |
318 | stroke
319 |
320 | Draws
321 | NO
322 |
323 |
324 |
325 |
326 | Class
327 | LineGraphic
328 | Head
329 |
330 | ID
331 | 31
332 | Info
333 | 4
334 |
335 | ID
336 | 42
337 | Points
338 |
339 | {140, 112.44951629638672}
340 | {235.00000095367432, 302}
341 |
342 | Style
343 |
344 | stroke
345 |
346 | HeadArrow
347 | FilledArrow
348 | Legacy
349 |
350 | LineType
351 | 1
352 | TailArrow
353 | 0
354 |
355 |
356 | Tail
357 |
358 | ID
359 | 40
360 | Info
361 | 3
362 |
363 |
364 |
365 | Class
366 | LineGraphic
367 | Head
368 |
369 | ID
370 | 30
371 |
372 | ID
373 | 41
374 | Points
375 |
376 | {140, 112.44951629638672}
377 | {235, 113}
378 |
379 | Style
380 |
381 | stroke
382 |
383 | HeadArrow
384 | FilledArrow
385 | Legacy
386 |
387 | LineType
388 | 1
389 | TailArrow
390 | 0
391 |
392 |
393 | Tail
394 |
395 | ID
396 | 40
397 | Info
398 | 3
399 |
400 |
401 |
402 | Bounds
403 | {{56, 88.999992592773424}, {43.619720000000001, 62.074218999999999}}
404 | Class
405 | ShapedGraphic
406 | ID
407 | 13
408 | ImageID
409 | 1
410 | Shape
411 | Rectangle
412 | Style
413 |
414 | fill
415 |
416 | Draws
417 | NO
418 |
419 | shadow
420 |
421 | Draws
422 | NO
423 |
424 | stroke
425 |
426 | Draws
427 | NO
428 |
429 |
430 |
431 |
432 | Class
433 | Group
434 | Graphics
435 |
436 |
437 | Bounds
438 | {{248.00000000000003, 132}, {37.948717948717949, 12}}
439 | Class
440 | ShapedGraphic
441 | ID
442 | 23
443 | Shape
444 | Rectangle
445 | Style
446 |
447 | shadow
448 |
449 | Draws
450 | NO
451 |
452 |
453 |
454 |
455 | Bounds
456 | {{248.00000000000003, 107.00000000000001}, {37.948717948717949, 12}}
457 | Class
458 | ShapedGraphic
459 | ID
460 | 24
461 | Shape
462 | Rectangle
463 | Style
464 |
465 | shadow
466 |
467 | Draws
468 | NO
469 |
470 |
471 |
472 |
473 | Bounds
474 | {{270.76923076923089, 94.000000000000014}, {125.2307692307692, 63}}
475 | Class
476 | ShapedGraphic
477 | ID
478 | 25
479 | Magnets
480 |
481 | {0, 1}
482 | {0, -1}
483 | {1, 0}
484 | {-1, 0}
485 |
486 | Shape
487 | Rectangle
488 | Style
489 |
490 | Text
491 |
492 | Text
493 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
494 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
495 | {\colortbl;\red255\green255\blue255;}
496 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
497 |
498 | \f0\fs24 \cf0 angularjs-webapp}
499 | VerticalPad
500 | 0
501 |
502 |
503 |
504 | ID
505 | 22
506 |
507 |
508 | Bounds
509 | {{235, 53}, {205, 120}}
510 | Class
511 | ShapedGraphic
512 | ID
513 | 30
514 | Magnets
515 |
516 | {0, 1}
517 | {0, -1}
518 | {1, 0}
519 | {-1, 0}
520 |
521 | Shape
522 | Cube
523 | Style
524 |
525 | Text
526 |
527 | Align
528 | 0
529 | Text
530 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
531 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
532 | {\colortbl;\red255\green255\blue255;}
533 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
534 |
535 | \f0\b\fs24 \cf0 Jetty, localhost:8080\
536 | }
537 | VerticalPad
538 | 0
539 |
540 | TextPlacement
541 | 0
542 |
543 |
544 | Class
545 | Group
546 | Graphics
547 |
548 |
549 | Bounds
550 | {{256.35999345779419, 321}, {32.820512820512832, 12}}
551 | Class
552 | ShapedGraphic
553 | ID
554 | 27
555 | Shape
556 | Rectangle
557 | Style
558 |
559 | shadow
560 |
561 | Draws
562 | NO
563 |
564 |
565 |
566 |
567 | Bounds
568 | {{256.35999345779419, 296}, {32.820512820512832, 12}}
569 | Class
570 | ShapedGraphic
571 | ID
572 | 28
573 | Shape
574 | Rectangle
575 | Style
576 |
577 | shadow
578 |
579 | Draws
580 | NO
581 |
582 |
583 |
584 |
585 | Bounds
586 | {{276.05230115010187, 283}, {108.30769230769231, 63}}
587 | Class
588 | ShapedGraphic
589 | ID
590 | 29
591 | Magnets
592 |
593 | {0, 1}
594 | {0, -1}
595 | {1, 0}
596 | {-1, 0}
597 |
598 | Shape
599 | Rectangle
600 | Style
601 |
602 | Text
603 |
604 | Text
605 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
606 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
607 | {\colortbl;\red255\green255\blue255;}
608 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
609 |
610 | \f0\fs24 \cf0 dw-server}
611 | VerticalPad
612 | 0
613 |
614 |
615 |
616 | ID
617 | 26
618 |
619 |
620 | Bounds
621 | {{235.00000095367432, 242}, {205, 120}}
622 | Class
623 | ShapedGraphic
624 | ID
625 | 31
626 | Magnets
627 |
628 | {0, 1}
629 | {0, -1}
630 | {1, 0}
631 | {-1, 0}
632 |
633 | Shape
634 | Cube
635 | Style
636 |
637 | Text
638 |
639 | Align
640 | 0
641 | Text
642 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
643 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
644 | {\colortbl;\red255\green255\blue255;}
645 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
646 |
647 | \f0\b\fs24 \cf0 Jetty, localhost:9000\
648 | }
649 | VerticalPad
650 | 0
651 |
652 | TextPlacement
653 | 0
654 |
655 |
656 | Bounds
657 | {{37, 59.899032592773438}, {103, 105.10096740722656}}
658 | Class
659 | ShapedGraphic
660 | ID
661 | 40
662 | Magnets
663 |
664 | {0, 1}
665 | {0, -1}
666 | {1, 0}
667 | {-1, 0}
668 |
669 | Shape
670 | Cube
671 | Style
672 |
673 | Text
674 |
675 | Align
676 | 0
677 | Text
678 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
679 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
680 | {\colortbl;\red255\green255\blue255;}
681 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
682 |
683 | \f0\b\fs24 \cf0 Web browser}
684 | VerticalPad
685 | 0
686 |
687 | TextPlacement
688 | 0
689 |
690 |
691 | GridInfo
692 |
693 | HPages
694 | 1
695 | KeepToScale
696 |
697 | Layers
698 |
699 |
700 | Lock
701 | NO
702 | Name
703 | Layer 1
704 | Print
705 | YES
706 | View
707 | YES
708 |
709 |
710 | LayoutInfo
711 |
712 | Animate
713 | NO
714 | circoMinDist
715 | 18
716 | circoSeparation
717 | 0.0
718 | layoutEngine
719 | dot
720 | neatoSeparation
721 | 0.0
722 | twopiSeparation
723 | 0.0
724 |
725 | Orientation
726 | 2
727 | PrintOnePage
728 |
729 | RowAlign
730 | 1
731 | RowSpacing
732 | 36
733 | SheetTitle
734 | Canvas 2
735 | UniqueID
736 | 2
737 | VPages
738 | 1
739 |
740 |
741 | ActiveLayerIndex
742 | 0
743 | AutoAdjust
744 |
745 | BackgroundGraphic
746 |
747 | Bounds
748 | {{0, 0}, {559.28001499176025, 782.8900146484375}}
749 | Class
750 | SolidGraphic
751 | ID
752 | 2
753 | Style
754 |
755 | shadow
756 |
757 | Draws
758 | NO
759 |
760 | stroke
761 |
762 | Draws
763 | NO
764 |
765 |
766 |
767 | BaseZoom
768 | 0
769 | CanvasOrigin
770 | {0, 0}
771 | ColumnAlign
772 | 1
773 | ColumnSpacing
774 | 36
775 | DisplayScale
776 | 1.000 cm = 1.000 cm
777 | GraphicsList
778 |
779 |
780 | Class
781 | LineGraphic
782 | Head
783 |
784 | ID
785 | 36
786 | Position
787 | 0.42412695288658142
788 |
789 | ID
790 | 39
791 | Points
792 |
793 | {217.86011953891327, 174.2958643200883}
794 | {165.61860843676374, 175.43999606370926}
795 |
796 | Style
797 |
798 | stroke
799 |
800 | HeadArrow
801 | 0
802 | Legacy
803 |
804 | LineType
805 | 1
806 | Pattern
807 | 1
808 | TailArrow
809 | 0
810 |
811 |
812 | Tail
813 |
814 | ID
815 | 15
816 |
817 |
818 |
819 | Bounds
820 | {{218.35999965667725, 152}, {163, 41}}
821 | Class
822 | ShapedGraphic
823 | ID
824 | 15
825 | Shape
826 | NoteShape
827 | Style
828 |
829 | fill
830 |
831 | Color
832 |
833 | b
834 | 0.4
835 | g
836 | 1
837 | r
838 | 0.8
839 |
840 |
841 |
842 | Text
843 |
844 | Text
845 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
846 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
847 | {\colortbl;\red255\green255\blue255;}
848 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
849 |
850 | \f0\fs24 \cf0 /api proxy to localhost:9000}
851 | VerticalPad
852 | 0
853 |
854 |
855 |
856 | Class
857 | LineGraphic
858 | Head
859 |
860 | ID
861 | 35
862 | Info
863 | 4
864 |
865 | ID
866 | 37
867 | Points
868 |
869 | {174.35999250411982, 279.5}
870 | {212.05230019642761, 279.5}
871 |
872 | Style
873 |
874 | stroke
875 |
876 | HeadArrow
877 | FilledArrow
878 | Legacy
879 |
880 | LineType
881 | 1
882 | TailArrow
883 | 0
884 |
885 |
886 | Tail
887 |
888 | ID
889 | 29
890 | Info
891 | 3
892 |
893 |
894 |
895 | Class
896 | LineGraphic
897 | Head
898 |
899 | ID
900 | 29
901 | Info
902 | 2
903 |
904 | ID
905 | 36
906 | Points
907 |
908 | {199.06460710672241, 122.00000000000001}
909 | {120.20614635027368, 248}
910 |
911 | Style
912 |
913 | stroke
914 |
915 | HeadArrow
916 | FilledArrow
917 | Legacy
918 |
919 | LineType
920 | 1
921 | TailArrow
922 | 0
923 |
924 |
925 | Tail
926 |
927 | ID
928 | 25
929 | Info
930 | 1
931 |
932 |
933 |
934 | Class
935 | Group
936 | Graphics
937 |
938 |
939 | Bounds
940 | {{192.35999250411993, 286}, {32.820512820512832, 12}}
941 | Class
942 | ShapedGraphic
943 | ID
944 | 33
945 | Shape
946 | Rectangle
947 | Style
948 |
949 | shadow
950 |
951 | Draws
952 | NO
953 |
954 |
955 |
956 |
957 | Bounds
958 | {{192.35999250411993, 261}, {32.820512820512832, 12}}
959 | Class
960 | ShapedGraphic
961 | ID
962 | 34
963 | Shape
964 | Rectangle
965 | Style
966 |
967 | shadow
968 |
969 | Draws
970 | NO
971 |
972 |
973 |
974 |
975 | Bounds
976 | {{212.05230019642764, 248}, {108.30769230769231, 63}}
977 | Class
978 | ShapedGraphic
979 | ID
980 | 35
981 | Magnets
982 |
983 | {0, 1}
984 | {0, -1}
985 | {1, 0}
986 | {-1, 0}
987 |
988 | Shape
989 | Rectangle
990 | Style
991 |
992 | Text
993 |
994 | Text
995 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
996 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
997 | {\colortbl;\red255\green255\blue255;}
998 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
999 |
1000 | \f0\fs24 \cf0 DB}
1001 | VerticalPad
1002 | 0
1003 |
1004 |
1005 |
1006 | ID
1007 | 32
1008 |
1009 |
1010 | Class
1011 | Group
1012 | Graphics
1013 |
1014 |
1015 | Bounds
1016 | {{113.67999172210693, 97}, {37.948717948717949, 12}}
1017 | Class
1018 | ShapedGraphic
1019 | ID
1020 | 23
1021 | Shape
1022 | Rectangle
1023 | Style
1024 |
1025 | shadow
1026 |
1027 | Draws
1028 | NO
1029 |
1030 |
1031 |
1032 |
1033 | Bounds
1034 | {{113.67999172210693, 72.000000000000014}, {37.948717948717949, 12}}
1035 | Class
1036 | ShapedGraphic
1037 | ID
1038 | 24
1039 | Shape
1040 | Rectangle
1041 | Style
1042 |
1043 | shadow
1044 |
1045 | Draws
1046 | NO
1047 |
1048 |
1049 |
1050 |
1051 | Bounds
1052 | {{136.44922249133782, 59.000000000000014}, {125.2307692307692, 63}}
1053 | Class
1054 | ShapedGraphic
1055 | ID
1056 | 25
1057 | Magnets
1058 |
1059 | {0, 1}
1060 | {0, -1}
1061 | {1, 0}
1062 | {-1, 0}
1063 |
1064 | Shape
1065 | Rectangle
1066 | Style
1067 |
1068 | Text
1069 |
1070 | Text
1071 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
1072 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
1073 | {\colortbl;\red255\green255\blue255;}
1074 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
1075 |
1076 | \f0\fs24 \cf0 angularjs-webapp}
1077 | VerticalPad
1078 | 0
1079 |
1080 |
1081 |
1082 | ID
1083 | 22
1084 |
1085 |
1086 | Bounds
1087 | {{100.67999172210693, 18}, {205, 120}}
1088 | Class
1089 | ShapedGraphic
1090 | ID
1091 | 30
1092 | Magnets
1093 |
1094 | {0, 1}
1095 | {0, -1}
1096 | {1, 0}
1097 | {-1, 0}
1098 |
1099 | Shape
1100 | Cube
1101 | Style
1102 |
1103 | Text
1104 |
1105 | Align
1106 | 0
1107 | Text
1108 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
1109 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
1110 | {\colortbl;\red255\green255\blue255;}
1111 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
1112 |
1113 | \f0\b\fs24 \cf0 Jetty, localhost:8080\
1114 | }
1115 | VerticalPad
1116 | 0
1117 |
1118 | TextPlacement
1119 | 0
1120 |
1121 |
1122 | Class
1123 | Group
1124 | Graphics
1125 |
1126 |
1127 | Bounds
1128 | {{46.359992504119845, 286}, {32.820512820512832, 12}}
1129 | Class
1130 | ShapedGraphic
1131 | ID
1132 | 27
1133 | Shape
1134 | Rectangle
1135 | Style
1136 |
1137 | shadow
1138 |
1139 | Draws
1140 | NO
1141 |
1142 |
1143 |
1144 |
1145 | Bounds
1146 | {{46.359992504119845, 261}, {32.820512820512832, 12}}
1147 | Class
1148 | ShapedGraphic
1149 | ID
1150 | 28
1151 | Shape
1152 | Rectangle
1153 | Style
1154 |
1155 | shadow
1156 |
1157 | Draws
1158 | NO
1159 |
1160 |
1161 |
1162 |
1163 | Bounds
1164 | {{66.052300196427524, 248}, {108.30769230769231, 63}}
1165 | Class
1166 | ShapedGraphic
1167 | ID
1168 | 29
1169 | Magnets
1170 |
1171 | {0, 1}
1172 | {0, -1}
1173 | {1, 0}
1174 | {-1, 0}
1175 |
1176 | Shape
1177 | Rectangle
1178 | Style
1179 |
1180 | Text
1181 |
1182 | Text
1183 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
1184 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
1185 | {\colortbl;\red255\green255\blue255;}
1186 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
1187 |
1188 | \f0\fs24 \cf0 dw-server}
1189 | VerticalPad
1190 | 0
1191 |
1192 |
1193 |
1194 | ID
1195 | 26
1196 |
1197 |
1198 | Bounds
1199 | {{25, 207}, {356.3599853515625, 120}}
1200 | Class
1201 | ShapedGraphic
1202 | ID
1203 | 31
1204 | Magnets
1205 |
1206 | {0, 1}
1207 | {0, -1}
1208 | {1, 0}
1209 | {-1, 0}
1210 |
1211 | Shape
1212 | Cube
1213 | Style
1214 |
1215 | Text
1216 |
1217 | Align
1218 | 0
1219 | Text
1220 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf390
1221 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
1222 | {\colortbl;\red255\green255\blue255;}
1223 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
1224 |
1225 | \f0\b\fs24 \cf0 Jetty, localhost:9000\
1226 | }
1227 | VerticalPad
1228 | 0
1229 |
1230 | TextPlacement
1231 | 0
1232 |
1233 |
1234 | GridInfo
1235 |
1236 | HPages
1237 | 1
1238 | KeepToScale
1239 |
1240 | Layers
1241 |
1242 |
1243 | Lock
1244 | NO
1245 | Name
1246 | Layer 1
1247 | Print
1248 | YES
1249 | View
1250 | YES
1251 |
1252 |
1253 | LayoutInfo
1254 |
1255 | Animate
1256 | NO
1257 | circoMinDist
1258 | 18
1259 | circoSeparation
1260 | 0.0
1261 | layoutEngine
1262 | dot
1263 | neatoSeparation
1264 | 0.0
1265 | twopiSeparation
1266 | 0.0
1267 |
1268 | Orientation
1269 | 2
1270 | PrintOnePage
1271 |
1272 | RowAlign
1273 | 1
1274 | RowSpacing
1275 | 36
1276 | SheetTitle
1277 | Canvas 1
1278 | UniqueID
1279 | 1
1280 | VPages
1281 | 1
1282 |
1283 |
1284 | SmartAlignmentGuidesActive
1285 | YES
1286 | SmartDistanceGuidesActive
1287 | YES
1288 | UseEntirePage
1289 |
1290 | WindowInfo
1291 |
1292 | CurrentSheet
1293 | 0
1294 | ExpandedCanvases
1295 |
1296 | Frame
1297 | {{567, -0}, {759, 878}}
1298 | ListView
1299 |
1300 | OutlineWidth
1301 | 142
1302 | RightSidebar
1303 |
1304 | ShowRuler
1305 |
1306 | Sidebar
1307 |
1308 | SidebarWidth
1309 | 120
1310 | VisibleRegion
1311 | {{-32, 0}, {624, 739}}
1312 | Zoom
1313 | 1
1314 | ZoomValues
1315 |
1316 |
1317 | Canvas 1
1318 | 1
1319 | 1
1320 |
1321 |
1322 | Canvas 2
1323 | 1
1324 | 1
1325 |
1326 |
1327 |
1328 |
1329 |
1330 |
--------------------------------------------------------------------------------
/doc/deployment_diagram.graffle/image1.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/perspilling/angularjs-dropwizard-example/7d4e1169757ead3e008627b9455fae6e84eab292/doc/deployment_diagram.graffle/image1.ai
--------------------------------------------------------------------------------
/doc/deployment_diagram.graffle/image2.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/perspilling/angularjs-dropwizard-example/7d4e1169757ead3e008627b9455fae6e84eab292/doc/deployment_diagram.graffle/image2.ai
--------------------------------------------------------------------------------
/doc/deployment_diagram.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/perspilling/angularjs-dropwizard-example/7d4e1169757ead3e008627b9455fae6e84eab292/doc/deployment_diagram.jpg
--------------------------------------------------------------------------------
/dw-server/README:
--------------------------------------------------------------------------------
1 | This is basically the example from: http://dropwizard.codahale.com/getting-started/
2 |
3 | Build it:
4 |
5 | > mvn package
6 |
7 | To start the Dropwizard Restful web services:
8 |
9 | > sh ./start_server.sh
10 |
--------------------------------------------------------------------------------
/dw-server/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | maven {
4 | name 'Gradle Shadow'
5 | url 'http://dl.bintray.com/content/johnrengelman/gradle-plugins'
6 | }
7 | }
8 | dependencies {
9 | classpath 'org.gradle.plugins:shadow:0.7.4'
10 | }
11 | }
12 | apply plugin: 'shadow'
13 |
14 | // Configure shadow (port of maven shade to gradle)
15 | shadow {
16 | exclude 'META-INF/*.DSA'
17 | exclude 'META-INF/*.RSA'
18 | exclude 'META-INF/*.SF'
19 | }
20 | build.dependsOn 'shadow' // wire shadow task into build cycle
21 |
22 | dependencies {
23 | compile libs.dropwizard_core, libs.dropwizard_jdbi, libs.dropwizard_db, libs.h2
24 | testCompile libs.jersey_client
25 | }
26 |
27 | jar {
28 | manifest {
29 | attributes 'Main-Class': 'no.kodemaker.ps.dw.eventservice.EventService'
30 | }
31 | }
32 |
33 | task runDwServer(type: JavaExec) {
34 | dependsOn 'shadow'
35 | description = "Run the server (on port 9000)"
36 | main = '-jar'
37 | args = [project.shadow.shadowJar, 'server', file('dw-server.yml')]
38 | }
39 |
--------------------------------------------------------------------------------
/dw-server/dw-server.yml:
--------------------------------------------------------------------------------
1 | #
2 | # For defaults, see: http://dropwizard.codahale.com/manual/core/#configuration-defaults
3 | #
4 | template: Hello, %s!
5 | defaultName: Stranger
6 |
7 |
8 | # Avoid using the default 8080 port for RESTFul services
9 | http:
10 | port: 9000
--------------------------------------------------------------------------------
/dw-server/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | no.kodemaker.ps
7 | angularjs-dropwizard-example
8 | 1.0-SNAPSHOT
9 |
10 |
11 | dw-server
12 | 1.0-SNAPSHOT
13 | jar
14 |
15 | dw-server
16 |
17 |
18 | UTF-8
19 | UTF-8
20 |
21 |
22 |
23 |
24 | com.yammer.dropwizard
25 | dropwizard-core
26 |
27 |
28 | com.yammer.dropwizard
29 | dropwizard-jdbi
30 |
31 |
32 | com.yammer.dropwizard
33 | dropwizard-db
34 |
35 |
36 | com.h2database
37 | h2
38 | 1.3.173
39 |
40 |
41 |
42 | com.sun.jersey
43 | jersey-client
44 | 1.12
45 | test
46 |
47 |
48 |
49 | junit
50 | junit
51 | test
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | org.apache.maven.plugins
60 | maven-shade-plugin
61 | 1.4
62 |
63 | true
64 |
65 |
66 | *:*
67 |
68 | META-INF/*.SF
69 | META-INF/*.DSA
70 | META-INF/*.RSA
71 |
72 |
73 |
74 |
75 |
76 |
77 | package
78 |
79 | shade
80 |
81 |
82 |
83 |
85 |
87 | no.kodemaker.ps.dw.eventservice.EventService
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/dw-server/src/main/java/no/kodemaker/ps/dw/eventservice/EventConfiguration.java:
--------------------------------------------------------------------------------
1 | package no.kodemaker.ps.dw.eventservice;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.yammer.dropwizard.config.Configuration;
5 | import org.hibernate.validator.constraints.NotEmpty;
6 |
7 | public class EventConfiguration extends Configuration {
8 | @NotEmpty
9 | @JsonProperty
10 | private String template;
11 |
12 | /*
13 | @Valid
14 | @NotNull
15 | @JsonProperty
16 | private DatabaseConfiguration databaseConfiguration = new DatabaseConfiguration();
17 | */
18 |
19 | @NotEmpty
20 | @JsonProperty
21 | private String defaultName = "Stranger";
22 |
23 | public String getTemplate() {
24 | return template;
25 | }
26 |
27 | public String getDefaultName() {
28 | return defaultName;
29 | }
30 |
31 | /*
32 | public DatabaseConfiguration getDatabaseConfiguration() {
33 | return databaseConfiguration;
34 | }
35 | */
36 | }
--------------------------------------------------------------------------------
/dw-server/src/main/java/no/kodemaker/ps/dw/eventservice/EventService.java:
--------------------------------------------------------------------------------
1 | package no.kodemaker.ps.dw.eventservice;
2 |
3 | import com.yammer.dropwizard.Service;
4 | import com.yammer.dropwizard.config.Bootstrap;
5 | import com.yammer.dropwizard.config.Environment;
6 | import no.kodemaker.ps.dw.eventservice.health.TemplateHealthCheck;
7 | import no.kodemaker.ps.dw.eventservice.persistence.PersonDao;
8 | import no.kodemaker.ps.dw.eventservice.representations.Person;
9 | import no.kodemaker.ps.dw.eventservice.resources.HelloWorldResource;
10 | import no.kodemaker.ps.dw.eventservice.resources.PersonsResource;
11 | import org.h2.jdbcx.JdbcConnectionPool;
12 | import org.skife.jdbi.v2.DBI;
13 |
14 | import java.util.ArrayList;
15 | import java.util.Collections;
16 | import java.util.List;
17 |
18 | /**
19 | * This main-class will be used by the start_server.sh script to start the server. It can also be
20 | * started up in the IDE, just remember to set the correct working directory and provide the expected
21 | * parameters: server dw-server.yml
22 | */
23 | public class EventService extends Service {
24 |
25 | private static List persons;
26 |
27 | static {
28 | persons = Collections.synchronizedList(new ArrayList());
29 | persons.add(new Person("Per", "per@kodemaker.no", "12345678"));
30 | persons.add(new Person("Magnus", "magnus@kodemaker.no"));
31 | persons.add(new Person("Ronny", "ronny@kodemaker.no"));
32 | persons.add(new Person("August", "august@kodemaker.no"));
33 | persons.add(new Person("Helge", "helge.jensen@finn.no"));
34 | }
35 |
36 | public static void main(String[] args) throws Exception {
37 | new EventService().run(args);
38 | }
39 |
40 | @Override
41 | public void initialize(Bootstrap bootstrap) {
42 | bootstrap.setName("dw-server"); // name must match the yaml config file
43 | }
44 |
45 | @Override
46 | public void run(EventConfiguration conf, Environment env) throws ClassNotFoundException {
47 | String template = conf.getTemplate();
48 | String defaultName = conf.getDefaultName();
49 |
50 | //DBIFactory factory = new DBIFactory();
51 | //final DBI jdbi = factory.build(env, conf.getDatabaseConfiguration(), "postgresql");
52 | // using in-memory data base here for simplicity
53 | JdbcConnectionPool jdbcConnectionPool = JdbcConnectionPool.create("jdbc:h2:mem:test", "username", "password");
54 | DBI jdbi = new DBI(jdbcConnectionPool);
55 | PersonDao personDao = jdbi.onDemand(PersonDao.class);
56 | personDao.createPersonTable();
57 | seedTheDatabase(personDao);
58 |
59 | env.addResource(new PersonsResource(personDao));
60 | env.addResource(new HelloWorldResource(template, defaultName));
61 | env.addHealthCheck(new TemplateHealthCheck(template));
62 | }
63 |
64 | private void seedTheDatabase(PersonDao personDao) {
65 | for (Person p : persons) {
66 | personDao.insert(p);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/dw-server/src/main/java/no/kodemaker/ps/dw/eventservice/health/TemplateHealthCheck.java:
--------------------------------------------------------------------------------
1 | package no.kodemaker.ps.dw.eventservice.health;
2 |
3 | import com.yammer.metrics.core.HealthCheck;
4 |
5 | public class TemplateHealthCheck extends HealthCheck {
6 | private final String template;
7 |
8 | public TemplateHealthCheck(String template) {
9 | super("template");
10 | this.template = template;
11 | }
12 |
13 | @Override
14 | protected Result check() throws Exception {
15 | // the following template string is expected: Hello, %s!
16 | final String saying = String.format(template, "TEST");
17 | if (!saying.contains("TEST")) {
18 | return Result.unhealthy("template doesn't include a name");
19 | }
20 | return Result.healthy();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/dw-server/src/main/java/no/kodemaker/ps/dw/eventservice/persistence/PersonDao.java:
--------------------------------------------------------------------------------
1 | package no.kodemaker.ps.dw.eventservice.persistence;
2 |
3 | import no.kodemaker.ps.dw.eventservice.representations.Person;
4 | import org.skife.jdbi.v2.sqlobject.Bind;
5 | import org.skife.jdbi.v2.sqlobject.BindBean;
6 | import org.skife.jdbi.v2.sqlobject.SqlQuery;
7 | import org.skife.jdbi.v2.sqlobject.SqlUpdate;
8 | import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
9 |
10 | import java.util.List;
11 |
12 | /**
13 | * @author Per Spilling
14 | */
15 | @RegisterMapper(PersonMapper.class)
16 | public interface PersonDao {
17 | @SqlUpdate("create table PERSON (id int auto_increment primary key, name varchar(80), email varchar(80), phone varchar(20))")
18 | void createPersonTable();
19 |
20 | @SqlUpdate("insert into PERSON (name, email, phone) values (:name, :email, :phone)")
21 | void insert(@BindBean Person person);
22 |
23 | @SqlUpdate("update PERSON set name = :p.name, email = :p.email, phone = :p.phone where id = :p.id")
24 | void update(@BindBean("p") Person person);
25 |
26 | @SqlQuery("select * from PERSON where id = :id")
27 | Person findById(@Bind("id") int id);
28 |
29 | @SqlQuery("select * from PERSON")
30 | List getAll();
31 |
32 | @SqlUpdate("delete from PERSON where id = :it")
33 | void deleteById(@Bind int id);
34 |
35 | @SqlUpdate("delete from PERSON where email = :it")
36 | void deleteByEmail(@Bind String email);
37 | }
38 |
--------------------------------------------------------------------------------
/dw-server/src/main/java/no/kodemaker/ps/dw/eventservice/persistence/PersonMapper.java:
--------------------------------------------------------------------------------
1 | package no.kodemaker.ps.dw.eventservice.persistence;
2 |
3 | import no.kodemaker.ps.dw.eventservice.representations.Person;
4 | import org.skife.jdbi.v2.StatementContext;
5 | import org.skife.jdbi.v2.tweak.ResultSetMapper;
6 |
7 | import java.sql.ResultSet;
8 | import java.sql.SQLException;
9 |
10 | /**
11 | * @author Per Spilling
12 | */
13 | public class PersonMapper implements ResultSetMapper {
14 | @Override
15 | public Person map(int i, ResultSet rs, StatementContext statementContext) throws SQLException {
16 | return new Person(rs.getInt("id"), rs.getString("name"), rs.getString("email"), rs.getString("phone"));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/dw-server/src/main/java/no/kodemaker/ps/dw/eventservice/representations/Person.java:
--------------------------------------------------------------------------------
1 | package no.kodemaker.ps.dw.eventservice.representations;
2 |
3 | /**
4 | * @author Per Spilling
5 | */
6 | public class Person {
7 | private Integer id; // PK
8 | private String name;
9 | private String email;
10 | private String phone;
11 |
12 | public Person() {
13 | }
14 |
15 | public Person(String name, String email) {
16 | this.name = name;
17 | this.email = email;
18 | }
19 |
20 | public Person(String name, String email, String phone) {
21 | this.name = name;
22 | this.email = email;
23 | this.phone = phone;
24 | }
25 |
26 | public Person(Integer id, String name, String email, String phone) {
27 | this.id = id;
28 | this.name = name;
29 | this.email = email;
30 | this.phone = phone;
31 | }
32 |
33 | public Integer getId() {
34 | return id;
35 | }
36 |
37 | public String getName() {
38 | return name;
39 | }
40 |
41 | public void setName(String name) {
42 | this.name = name;
43 | }
44 |
45 | public String getEmail() {
46 | return email;
47 | }
48 |
49 | public void setEmail(String email) {
50 | this.email = email;
51 | }
52 |
53 | public String getPhone() {
54 | return phone;
55 | }
56 |
57 | public void setPhone(String phone) {
58 | this.phone = phone;
59 | }
60 |
61 | @Override
62 | public boolean equals(Object o) {
63 | if (this == o) return true;
64 | if (o == null || getClass() != o.getClass()) return false;
65 |
66 | Person person = (Person) o;
67 |
68 | if (email != null ? !email.equals(person.email) : person.email != null) return false;
69 | if (id != null ? !id.equals(person.id) : person.id != null) return false;
70 | if (name != null ? !name.equals(person.name) : person.name != null) return false;
71 | if (phone != null ? !phone.equals(person.phone) : person.phone != null) return false;
72 |
73 | return true;
74 | }
75 |
76 | @Override
77 | public int hashCode() {
78 | int result = id != null ? id.hashCode() : 0;
79 | result = 31 * result + (name != null ? name.hashCode() : 0);
80 | result = 31 * result + (email != null ? email.hashCode() : 0);
81 | result = 31 * result + (phone != null ? phone.hashCode() : 0);
82 | return result;
83 | }
84 |
85 | public boolean isValid() {
86 | return name != null && email != null;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/dw-server/src/main/java/no/kodemaker/ps/dw/eventservice/representations/Saying.java:
--------------------------------------------------------------------------------
1 | package no.kodemaker.ps.dw.eventservice.representations;
2 |
3 | /**
4 | * Used for responding to hello requests.
5 | */
6 | public class Saying {
7 | private final long id;
8 | private final String content;
9 |
10 | public Saying(long id, String content) {
11 | this.id = id;
12 | this.content = content;
13 | }
14 |
15 | public long getId() {
16 | return id;
17 | }
18 |
19 | public String getContent() {
20 | return content;
21 | }
22 | }
--------------------------------------------------------------------------------
/dw-server/src/main/java/no/kodemaker/ps/dw/eventservice/resources/HelloWorldResource.java:
--------------------------------------------------------------------------------
1 | package no.kodemaker.ps.dw.eventservice.resources;
2 |
3 | import com.google.common.base.Optional;
4 | import com.yammer.metrics.annotation.Timed;
5 | import no.kodemaker.ps.dw.eventservice.representations.Saying;
6 |
7 | import javax.ws.rs.GET;
8 | import javax.ws.rs.Path;
9 | import javax.ws.rs.Produces;
10 | import javax.ws.rs.QueryParam;
11 | import javax.ws.rs.core.MediaType;
12 | import java.util.concurrent.atomic.AtomicLong;
13 |
14 | @Path("/hello-world")
15 | @Produces(MediaType.APPLICATION_JSON)
16 | public class HelloWorldResource {
17 | private final String template;
18 | private final String defaultName;
19 | private final AtomicLong counter;
20 |
21 | public HelloWorldResource(String template, String defaultName) {
22 | this.template = template;
23 | this.defaultName = defaultName;
24 | this.counter = new AtomicLong();
25 | }
26 |
27 | @GET
28 | @Timed
29 | public Saying sayHello(@QueryParam("name") Optional name) {
30 | return new Saying(counter.incrementAndGet(),
31 | String.format(template, name.or(defaultName)));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/dw-server/src/main/java/no/kodemaker/ps/dw/eventservice/resources/PersonsResource.java:
--------------------------------------------------------------------------------
1 | package no.kodemaker.ps.dw.eventservice.resources;
2 |
3 | import com.yammer.metrics.annotation.Timed;
4 | import no.kodemaker.ps.dw.eventservice.persistence.PersonDao;
5 | import no.kodemaker.ps.dw.eventservice.representations.Person;
6 |
7 | import javax.ws.rs.*;
8 | import javax.ws.rs.core.MediaType;
9 | import javax.ws.rs.core.Response;
10 | import java.util.List;
11 |
12 | /**
13 | * The resource used to handle Person requests.
14 | *
15 | * @author Per Spilling
16 | */
17 | @Path("/persons")
18 | @Produces(MediaType.APPLICATION_JSON)
19 | @Consumes(MediaType.APPLICATION_JSON)
20 | public class PersonsResource {
21 | private PersonDao personDao;
22 |
23 | public PersonsResource(PersonDao dao) {
24 | personDao = dao;
25 | }
26 |
27 | @GET
28 | @Path("/{id}")
29 | @Timed
30 | public Person getPerson(@PathParam("id") Integer id) {
31 | Person p = personDao.findById(id);
32 | if (p != null) {
33 | return p;
34 | } else {
35 | throw new WebApplicationException(Response.Status.NOT_FOUND);
36 | }
37 | }
38 |
39 | @GET
40 | @Timed
41 | public List listPersons() {
42 | return personDao.getAll();
43 | }
44 |
45 | @POST
46 | @Timed
47 | public void save(Person person) {
48 | if (person != null && person.isValid()) {
49 | if (person.getId() != null) {
50 | personDao.update(person);
51 | } else {
52 | personDao.insert(person);
53 | }
54 | }
55 | }
56 |
57 | @DELETE
58 | @Path("/{id}")
59 | @Timed
60 | @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN})
61 | public void deletePerson(@PathParam("id") Integer id) {
62 | /**
63 | * Note: AngularJS $resource will send a DELETE request as content-type test/plain for some reason;
64 | * so therefore we must add MediaType.TEXT_PLAIN here.
65 | */
66 | if (personDao.findById(id) != null) {
67 | personDao.deleteById(id);
68 | } else {
69 | throw new WebApplicationException(Response.Status.NOT_FOUND);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/dw-server/src/test/java/no/kodemaker/example/dw/hello/client/HelloWorldClient.java:
--------------------------------------------------------------------------------
1 | package no.kodemaker.example.dw.hello.client;
2 |
3 | import com.sun.jersey.api.client.Client;
4 | import com.sun.jersey.api.client.WebResource;
5 |
6 | import java.text.DecimalFormat;
7 |
8 | public class HelloWorldClient {
9 | static public void main(String[] args) {
10 | Client client = Client.create();
11 | WebResource resource = client.resource("http://eagle.local:8080/hello-world");
12 | int num_of_requests = 10000;
13 | long startTime = System.currentTimeMillis();
14 | for (int i = 0; i < num_of_requests; i++) {
15 | String result = resource.queryParam("name", "Per").get(String.class);
16 | System.out.println("result=" + result);
17 | }
18 | long endTime = System.currentTimeMillis();
19 | float duration = endTime - startTime;
20 | String seconds = new DecimalFormat("#.####").format(duration/1000);
21 | System.out.println("Duration = " + seconds.toString());
22 | System.out.println("Request/sec = " + Float.toString((num_of_requests/duration)*1000));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/dw-server/start_server.sh:
--------------------------------------------------------------------------------
1 | java -jar target/dw-server-1.0-SNAPSHOT.jar server dw-server.yml
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/perspilling/angularjs-dropwizard-example/7d4e1169757ead3e008627b9455fae6e84eab292/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Aug 24 17:47:02 CEST 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=http\://services.gradle.org/distributions/gradle-1.7-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | no.kodemaker.ps
6 | angularjs-dropwizard-example
7 | 1.0-SNAPSHOT
8 | pom
9 |
10 | angularjs-dropwizard-example
11 |
12 |
13 | Kodemaker Systemutvikling AS
14 | http://www.kodemaker.no/
15 |
16 |
17 |
18 | dw-server
19 | angularjs-webapp
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | UTF-8
28 |
29 | yyyy-MM-dd HH:mm
30 | 1.7
31 | 1.7
32 | 0.6.2
33 | 9.1-901.jdbc4
34 |
35 |
40 | 9.4.41.v20210516
41 |
42 |
43 | 2.2.3
44 |
45 |
46 |
47 |
48 |
49 |
50 |
55 |
56 |
57 |
58 | com.yammer.dropwizard
59 | dropwizard-core
60 | ${dw.version}
61 |
62 |
63 |
64 |
65 | com.yammer.dropwizard
66 | dropwizard-jdbi
67 | ${dw.version}
68 |
69 |
70 | com.yammer.dropwizard
71 | dropwizard-db
72 | ${dw.version}
73 |
74 |
75 |
76 |
81 |
82 | org.eclipse.jetty
83 | jetty-webapp
84 | ${jetty.version}
85 |
86 |
87 |
88 |
89 | org.eclipse.jetty
90 | jetty-servlets
91 | ${jetty.version}
92 |
93 |
94 |
95 |
96 | org.glassfish.web
97 | javax.servlet.jsp
98 | ${glassfish.javax.version}
99 |
100 |
101 |
102 |
103 | postgresql
104 | postgresql
105 | ${postgresql.version}
106 |
107 |
108 |
109 |
110 | com.google.guava
111 | guava
112 | 13.0.1
113 |
114 |
115 |
116 |
117 | junit
118 | junit
119 | 4.13.1
120 | test
121 |
122 |
123 |
124 | org.mockito
125 | mockito-all
126 | 1.9.0
127 | test
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 | false
142 | src/main/java
143 |
144 | **
145 |
146 |
147 | **/*.java
148 |
149 |
150 |
151 | false
152 | src/main/resources
153 |
154 | **
155 |
156 |
157 |
158 |
159 |
166 |
167 |
168 |
169 |
170 |
171 |
172 | false
173 | src/test/resources
174 |
175 |
176 | false
177 | src/test/java
178 |
179 | **
180 |
181 |
182 | **/*.java
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 | org.apache.maven.plugins
191 | maven-compiler-plugin
192 | 2.3.2
193 |
194 | ${targetJdk}
195 | ${targetJdk}
196 | UTF-8
197 |
198 |
199 |
200 |
201 | org.apache.maven.plugins
202 | maven-deploy-plugin
203 | 2.7
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
228 |
229 |
230 |
231 |
232 |
238 |
239 |
255 |
256 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':dw-server', ':angularjs-webapp'
2 |
3 |
--------------------------------------------------------------------------------