opennms
Version:
Client API for the OpenNMS network monitoring platform
221 lines (198 loc) • 7.67 kB
text/typescript
import {IFilterProcessor} from '../api/IFilterProcessor';
import {IHasHTTP} from '../api/IHasHTTP';
import {IOnmsHTTP} from '../api/IOnmsHTTP';
import {OnmsError} from '../api/OnmsError';
import {Filter} from '../api/Filter';
import {OnmsHTTPOptions} from '../api/OnmsHTTPOptions';
import {SearchProperty} from '../api/SearchProperty';
import {SearchPropertyType} from '../api/SearchPropertyType';
import {log, catDao} from '../api/Log';
import {V1FilterProcessor} from './V1FilterProcessor';
import {V2FilterProcessor} from './V2FilterProcessor';
import {PropertiesCache} from './PropertiesCache';
import {BaseDAO} from './BaseDAO';
/** @hidden */
// tslint:disable-next-line
const moment = require('moment');
/** @hidden */
// tslint:disable-next-line
import {Moment} from 'moment';
import {IValueProvider} from './IValueProvider';
/**
* An abstract data access layer API, meant to (somewhat) mirror the DAO interfaces
* inside OpenNMS. Used to retrieve model data like alarms, events, etc. from the
* OpenNMS ReST API in a consistent way.
*
* @module AbstractDAO
* @param K the ID/key type (number, string, etc.)
* @param T the model type (OnmsAlarm, OnmsEvent, etc.)
*/
export abstract class AbstractDAO<K, T> extends BaseDAO implements IValueProvider {
/**
* Returns the Promise for a [[IFilterProcessor]].
* @returns {Promise}
*/
public async getFilterProcessor(): Promise<IFilterProcessor> {
switch (this.getApiVersion()) {
case 2:
return this.getPropertiesCache().then((cache) => {
return new V2FilterProcessor(cache);
});
default:
return Promise.resolve(new V1FilterProcessor());
}
}
/**
* Retrieve a model object.
* @param id - the ID of the object
*/
public abstract async get(id: K): Promise<T>;
/**
* Find all model objects given an optional filter.
* @param filter - the filter to use when retrieving a list of model objects
*/
public abstract async find(filter?: Filter): Promise<T[]>;
/**
* Get the list properties that can be used in queries.
* @version ReST v2
*/
public async searchProperties(): Promise<SearchProperty[]> {
return this.getPropertiesCache().then((cache) => {
return cache.getProperties();
});
}
/**
* Gets the property identified by the id if it exists.
*
* @param id The id to search the property by.
*/
public async searchProperty(id: string): Promise<SearchProperty> {
return this.getPropertiesCache().then((cache) => {
return cache.getProperty(id);
});
}
/**
* Returns or creates the [[PropertiesCache]] for this dao.
*
* @return the [[PropertiesCache]] for this dao. It is created if it does not exist.
*/
public async getPropertiesCache(): Promise<PropertiesCache> {
if (this.getApiVersion() === 1) {
throw new OnmsError('Search property metadata is only available in OpenNMS ' +
'versions that support the ReSTv2 API.');
}
// Cache not yet initialized
if (!PropertiesCache.get(this)) {
return this.getOptions().then((opts) => {
opts.headers.accept = 'application/json';
return this.http.get(this.searchPropertyPath(), opts).then((result) => {
const searchProperties = this.parseResultList(result, 'searchProperty',
this.searchPropertyPath(), (prop) => {
return this.toSearchProperty(prop);
});
PropertiesCache.put(this, searchProperties);
return Promise.resolve(PropertiesCache.get(this));
});
});
}
// Cache already initialized, use value
return Promise.resolve(PropertiesCache.get(this));
}
/**
* Finds the values for the given propertyId, if it exists.
*
* @param {string} propertyId The propertyId to find the values for
* @param options Some additional options. May be implementer dependent, such as limit, or value restrictions
* @returns {Promise<any>} A promise containing the values.
*/
public async findValues(propertyId: string, options?: any): Promise<any> {
return this.searchProperty(propertyId).then((property) => {
return this.getOptions().then((opts) => {
const path = this.searchPropertyPath() + '/' + property.id;
opts.headers.accept = 'application/json';
if (options) {
Object.assign(opts, options);
}
return this.http.get(path, opts).then((result) => {
return this.parseResultList(result, 'value', path, (value) => value);
});
});
});
}
/**
* The path to retrieve search properties for this DAO.
*/
protected abstract searchPropertyPath(): string;
/**
* Fetches the data from the result and verfifes that the <code>dataFieldName</code> exists in the data property.
* If it does not exist, an exception is thrown.
*
* @param result The result to fetch the data from
* @param dataFieldName The property name (basically <code>result.data[dataFieldName]</code>.
* @param path The path where the result was fetched from. This is for error handling
* @param mapCallbackFunction Callback function to convert each entry from <code>result.data[dataFieldName]</code>.
*/
protected parseResultList(result: any, dataFieldName: string, path: string, mapCallbackFunction: any): any {
let data = result.data;
if (this.getCount(data) > 0 && data[dataFieldName]) {
data = data[dataFieldName];
} else {
data = [];
}
if (!Array.isArray(data)) {
throw new OnmsError('Expected an array but got "' + (typeof data) + '" instead: ' + path);
}
if (mapCallbackFunction) {
return data.map(mapCallbackFunction);
}
return data;
}
/**
* Create an [[OnmsHTTPOptions]] object for DAO calls given an optional filter.
* @param filter - the filter to use
*/
protected async getOptions(filter?: Filter): Promise<OnmsHTTPOptions> {
return Promise.resolve(new OnmsHTTPOptions())
.then((options) => {
if (this.useJson()) {
options.headers.accept = 'application/json';
} else {
// always use application/xml in DAO calls when we're not sure how
// usable JSON output will be.
options.headers.accept = 'application/xml';
}
if (filter) {
return this.getFilterProcessor().then((processor) => {
options.parameters = processor.getParameters(filter);
return options;
});
}
return options;
});
}
/**
* Generate a [[SearchProperty]] from the given dictionary.
* @hidden
*/
protected toSearchProperty(data: any): SearchProperty {
if (!data) {
return null;
}
const prop = new SearchProperty(this);
prop.id = data.id;
prop.name = data.name;
prop.orderBy = !!data.orderBy;
prop.type = SearchPropertyType.forId(data.type);
prop.values = data.values;
return prop;
}
/**
* Retrieve the API version from the currently configured server.
*/
protected getApiVersion(): number {
if (this.http === undefined || this.http.server === undefined || this.http.server.metadata === undefined) {
throw new OnmsError('Server meta-data must be populated prior to making DAO calls.');
}
return this.http.server.metadata.apiVersion();
}
}