UNPKG

nakedobjects.spa

Version:

Single Page Application client for a Naked Objects application.

283 lines 12.9 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; import { Injectable } from '@angular/core'; import { Request, RequestOptions, Headers, RequestMethod, ResponseContentType } from '@angular/http'; import * as Models from './models'; import { Subject } from 'rxjs/Subject'; import { ConfigService } from './config.service'; import { SimpleLruCache } from './simple-lru-cache'; import { AuthHttp } from 'angular2-jwt'; import 'rxjs/add/operator/toPromise'; import each from 'lodash/each'; import reduce from 'lodash/reduce'; var RepLoaderService = (function () { function RepLoaderService(http, configService) { var _this = this; this.http = http; this.configService = configService; this.loadingCount = 0; this.loadingCountSource = new Subject(); this.loadingCount$ = this.loadingCountSource.asObservable(); // use our own LRU cache this.cache = new SimpleLruCache(this.configService.config.httpCacheDepth); this.populate = function (model, ignoreCache) { var response = model; var config = new RequestOptions({ withCredentials: true, url: model.getUrl(), method: model.method, body: model.getBody() }); return _this.httpPopulate(config, !!ignoreCache, response); }; this.retrieve = function (map, rc, digest) { var response = new rc(); var config = _this.setConfigFromMap(map, digest); return _this.httpPopulate(config, true, response); }; this.validate = function (map, digest) { var config = _this.setConfigFromMap(map, digest); return _this.httpValidate(config); }; this.retrieveFromLink = function (link, parms) { if (link) { var response = link.getTarget(); var urlParms = ""; if (parms) { var urlParmString = reduce(parms, function (result, n, key) { return (result === "" ? "" : result + "&") + key + "=" + n; }, ""); urlParms = urlParmString !== "" ? "?" + urlParmString : ""; } var config = new RequestOptions({ method: link.method(), url: link.href() + urlParms, withCredentials: true }); return _this.httpPopulate(config, true, response); } return Promise.reject("link must not be null"); }; this.invoke = function (action, parms, urlParms) { var invokeMap = action.getInvokeMap(); if (invokeMap) { each(urlParms, function (v, k) { return invokeMap.setUrlParameter(k, v); }); each(parms, function (v, k) { return invokeMap.setParameter(k, v); }); return _this.retrieve(invokeMap, Models.ActionResultRepresentation); } return Promise.reject("attempting to invoke uninvokable action " + action.actionId()); }; this.clearCache = function (url) { _this.cache.remove(url); }; this.addToCache = function (url, m) { _this.cache.add(url, m); }; this.getFile = function (url, mt, ignoreCache) { if (ignoreCache) { // clear cache of existing values _this.cache.remove(url); } else { var blob = _this.cache.get(url); if (blob) { return Promise.resolve(blob); } } var config = new RequestOptions({ method: "GET", url: url, responseType: ResponseContentType.Blob, headers: new Headers({ "Accept": mt }) }); var request = new Request(config); return _this.http.request(request) .toPromise() .then(function (r) { var blob = r.blob(); _this.cache.add(config.url, blob); return blob; }) .catch(function (r) { var originalUrl = config.url || "Unknown url"; r.url = r.url || originalUrl; return _this.handleError(r, originalUrl); }); }; this.uploadFile = function (url, mt, file) { var config = new RequestOptions({ method: "POST", url: url, body: file, headers: new Headers({ "Content-Type": mt }) }); var request = new Request(config); return _this.http.request(request) .toPromise() .then(function () { return Promise.resolve(true); }) .catch(function () { return Promise.resolve(false); }); }; } RepLoaderService.prototype.addIfMatchHeader = function (config, digest) { if (digest && (config.method === RequestMethod.Post || config.method === RequestMethod.Put || config.method === RequestMethod.Delete)) { config.headers = new Headers({ "If-Match": digest }); } }; RepLoaderService.prototype.handleInvalidResponse = function (rc) { var rr = new Models.ErrorWrapper(rc, Models.ClientErrorCode.ConnectionProblem, "The response from the client was not parseable as a RestfulObject json Representation "); return Promise.reject(rr); }; RepLoaderService.prototype.isObjectUrl = function (url) { var segments = url.split('/'); return segments.length >= 4 && segments[3] === "objects"; }; RepLoaderService.prototype.handleError = function (response, originalUrl) { var category; var error; if (response.status === Models.HttpStatusCode.InternalServerError) { // this error should contain an error representatation if (Models.isErrorRepresentation(response.json())) { var errorRep = new Models.ErrorRepresentation(); errorRep.populate(response.json()); category = Models.ErrorCategory.HttpServerError; error = errorRep; } else { return this.handleInvalidResponse(Models.ErrorCategory.HttpServerError); } } else if (response.status <= 0) { // failed to connect category = Models.ErrorCategory.ClientError; error = "Failed to connect to server: " + (response.url || "unknown"); } else { category = Models.ErrorCategory.HttpClientError; var message = (response.headers && response.headers.get("warning")) || "Unknown client HTTP error"; if (response.status === Models.HttpStatusCode.BadRequest || response.status === Models.HttpStatusCode.UnprocessableEntity) { // these errors should contain a map error = new Models.ErrorMap(response.json(), response.status, message); } else if (response.status === Models.HttpStatusCode.NotFound && this.isObjectUrl(originalUrl)) { // were looking for an object an got not found - object may be deleted // treat as http problem. category = Models.ErrorCategory.HttpClientError; error = "Failed to connect to server: " + (response.url || "unknown"); } else if (response.status === Models.HttpStatusCode.NotFound) { // general not found other than object - assume client programming error category = Models.ErrorCategory.ClientError; error = "Failed to connect to server: " + (response.url || "unknown"); } else { error = message; } } var rr = new Models.ErrorWrapper(category, response.status, error, originalUrl); return Promise.reject(rr); }; RepLoaderService.prototype.httpValidate = function (config) { var _this = this; this.loadingCountSource.next(++(this.loadingCount)); return this.http.request(new Request(config)) .toPromise() .then(function () { _this.loadingCountSource.next(--(_this.loadingCount)); return Promise.resolve(true); }) .catch(function (r) { _this.loadingCountSource.next(--(_this.loadingCount)); var originalUrl = config.url || "Unknown url"; r.url = r.url || originalUrl; return _this.handleError(r, originalUrl); }); }; // special handler for case where we receive a redirected object back from server // instead of an actionresult. Wrap the object in an actionresult and then handle normally RepLoaderService.prototype.handleRedirectedObject = function (response, data) { if (response instanceof Models.ActionResultRepresentation && Models.isIDomainObjectRepresentation(data)) { var actionResult = { resultType: "object", result: data, links: [], extensions: {} }; return actionResult; } return data; }; RepLoaderService.prototype.isValidResponse = function (data) { return Models.isResourceRepresentation(data); }; RepLoaderService.prototype.httpPopulate = function (config, ignoreCache, response) { var _this = this; if (!config.url) { throw new Error("Request must have a URL"); } var requestUrl = config.url; if (ignoreCache) { // clear cache of existing values this.cache.remove(requestUrl); } else { var cachedValue = this.cache.get(requestUrl); if (cachedValue) { response.populate(cachedValue); response.keySeparator = this.configService.config.keySeparator; return Promise.resolve(response); } } this.loadingCountSource.next(++(this.loadingCount)); return this.http.request(new Request(config)) .toPromise() .then(function (r) { _this.loadingCountSource.next(--(_this.loadingCount)); var asJson = r.json(); if (!_this.isValidResponse(asJson)) { return _this.handleInvalidResponse(Models.ErrorCategory.ClientError); } var representation = _this.handleRedirectedObject(response, asJson); _this.cache.add(requestUrl, representation); response.populate(representation); response.etagDigest = (r.headers && r.headers.get("ETag")) || ""; response.keySeparator = _this.configService.config.keySeparator; return Promise.resolve(response); }) .catch(function (r) { _this.loadingCountSource.next(--(_this.loadingCount)); r.url = r.url || requestUrl; return _this.handleError(r, requestUrl); }); }; RepLoaderService.prototype.setConfigFromMap = function (map, digest) { var config = new RequestOptions({ withCredentials: true, url: map.getUrl(), method: map.method, body: map.getBody() }); this.addIfMatchHeader(config, digest); return config; }; RepLoaderService.prototype.logoff = function () { this.cache.removeAll(); }; return RepLoaderService; }()); RepLoaderService = __decorate([ Injectable(), __metadata("design:paramtypes", [AuthHttp, ConfigService]) ], RepLoaderService); export { RepLoaderService }; //# sourceMappingURL=rep-loader.service.js.map