All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.reprezen.genflow.rapidml.nodejs.AppGenerator.xtend Maven / Gradle / Ivy

package com.reprezen.genflow.rapidml.nodejs

import com.fasterxml.jackson.databind.ObjectMapper
import com.reprezen.genflow.api.GenerationException
import com.reprezen.genflow.api.template.IGenTemplateContext
import com.reprezen.genflow.rapidml.nodejs.NodejsGenerator.Generator
import java.util.List
import java.util.Map

class AppGenerator implements Generator {

	val static builtinDaoAdapters = #{
		'ES' -> './lib/daoAdapters/ES_DAO'
	}

	val static mapper = new ObjectMapper();

	val String metadataFile;
	val IGenTemplateContext context;

	new(String metadataFile, IGenTemplateContext context) {
		this.metadataFile = metadataFile;
		this.context = context;
	}

	override generate() throws GenerationException {
		val port = context.genTargetParameters.get("servicePort") ?: 3000;
		val baseUrl = context.genTargetParameters.get("baseURL");
		val linksPropertyName = context.genTargetParameters.get("linksPropertyName");

		'''
			const url = require('url');
			const express = require('express');
			const winston = require('winston');
			const expressWinston = require('express-winston');
			const fillEnv = require('./lib/fillEnv');
			const fs = require('fs');
			const walk = require('walk');
			const EventEmitter = require('events');
			const http = require('http');
			
			const defaultOptions = {
					port: '«port»',
					baseUrl: '«baseUrl»',
					mainMetadataFile: '«metadataFile»',
					otherMetadataFiles: [
						«FOR mdFile : otherMetadatas SEPARATOR ","»
							'«mdFile»'
						«ENDFOR»
					],
					daoAdapter: '«daoAdapter»',
					daoOptions: «daoAdapterOptions»,
					middlewareModules: [
						«FOR mw : middlewares SEPARATOR ','»
							'«mw»'
						«ENDFOR»
					],
					setupModules: [
						«FOR setup : setupModules SEPARATOR ','»
							'«setup»'
						«ENDFOR»
					]
			}
			
			class App extends EventEmitter {
				constructor(options = {}) {
					super();
					this.options = Object.assign({}, defaultOptions, options);
					this.options = fillEnv(this.options);
				}
				
				setup() {
					this.pSetup = loadMetadata(this.options).then(metadata => {
						this.metadata = metadata;
						this.dao = loadDAO(this.options, this);
						return createApp(this.options, this);
					}).then(app => {
						this.app = app;
						loadSetupModules(this.options, this);
					});
					return this;
				}
				
				run() {
					if (!this.pSetup) {
						setup();
					}
					this.pSetup.then(_ => {
						this.server = new http.createServer(this.app);
						this.server.listen(this.options.port, _ => {
							this.emit('ready', this.options.port);
						});
					}).catch(error => {
						console.error(error);
					});
				}
				
				close() {
					this.server.close();
				}
			}
			
			function loadMetadata(options) {
				const Metadata = require('./lib/Metadata');	let metadata = new Metadata();
				let p = metadata.ingest(options.mainMetadataFile);
				for (let mdfile of options.otherMetadataFiles) {
					p = p.then(_ => metadata.ingest(mdfile));
				}
				p = p.then(_ => metadata.resolve());
				return p.then(_ => metadata);
			}
			
			function loadDAO(options, self) {
				const DataAccessObject = require('./lib/DataAccessObject');
				let adapterClass = require(options.daoAdapter);
				return new DataAccessObject(adapterClass, options.daoOptions, self.metadata, options.baseUrl);
			}
			
			function createApp(options, self) {
				let app = new express();
				app.locals.baseUrl = options.baseUrl;
				app.locals.basePath = url.parse(options.baseUrl).pathname;
				app.locals.daoLimits = self.dao.adapter.constructor.limits;
				app.locals.linksPropertyName = '«linksPropertyName»';
				app.use(expressWinston.logger({
					transports: [new winston.transports.Console()]
				}));
				for (let mw of options.middlewareModules) {
					app.use(require(mw));
				}
				return setupPaths(app, self.dao).then(_ => {
					// this has to go after all the routes have been established
					app.use(expressWinston.errorLogger({
						transports: [new winston.transports.Console({dumpExceptions: true, showStack: true, json:true})]
					}));
					// suppress standard express error logging
					app.use((req,res,next,error) => {});
					return app;
				});
			}
			
			function setupPaths(app, dao) {
				return new Promise((resolve, reject) => {
					walker = walk.walk('handlers');
					walker.on('file', (root, stat, next) => {
						let path = `./${root}/${stat.name}`;
						let handlerClass = require(path);
						new handlerClass(app, dao);
						next();
					});
					walker.on('errors', () => reject('Failed to load resource handlers'));
					walker.on('end', () => resolve());
				});	
			}
			
			function loadSetupModules(options, self) {
				for (let setupModule of options.setupModules) {
					require(setupModule)(self.metadata, self.dao, self.app);
				}
			}
			
			if (require.main === module) {
				let app = new App()
				app.setup();
				app.on('ready', port => {
					console.log(`Listening on port ${port}`);
				});
				app.run();
			}
			
			module.exports = App;
		'''
	}

	def private getDaoAdapter() {
		val adapter = context.genTargetParameters.get('daoAdapter')
		if(builtinDaoAdapters.containsKey(adapter)) builtinDaoAdapters.get(adapter) else adapter
	}

	def private getDaoAdapterOptions() {
		var options = context.genTargetParameters.get('daoAdapterOptions') ?: "{}";
		if(options instanceof Map) mapper.writerWithDefaultPrettyPrinter().writeValueAsString(options);
	}

	def private getOtherMetadatas() {
		context.genTargetParameters.get('additionalMetadata') as List ?: #[]
	}

	def private getMiddlewares() {
		context.genTargetParameters.get('middlewareModules') as List ?: #[]
	}

	def private getSetupModules() {
		context.genTargetParameters.get('setupModules') as List ?: #[]
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy