jive-sdk
Version:
Node.js SDK for Jive Software to assist with the development of add-ons
523 lines (418 loc) • 16.1 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Jive SDK Source: jive-sdk-service/lib/definitionSetup.js</title>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/sunlight.default.css">
<link type="text/css" rel="stylesheet" href="styles/site.spacelab.css">
</head>
<body>
<div class="container-fluid">
<div class="navbar navbar-fixed-top navbar-inverse">
<div class="navbar-inner">
<a class="brand" href="index.html">Jive SDK</a>
<ul class="nav">
<li class="dropdown">
<a href="modules.list.html" class="dropdown-toggle" data-toggle="dropdown">Modules<b
class="caret"></b></a>
<ul class="dropdown-menu ">
<li>
<a href="module-abstractDefinitions.html">abstractDefinitions</a>
</li>
<li>
<a href="module-abstractInstances.html">abstractInstances</a>
</li>
<li>
<a href="module-addOnRoutes.html">addOnRoutes</a>
</li>
<li>
<a href="module-api.html">api</a>
</li>
<li>
<a href="module-community.html">community</a>
</li>
<li>
<a href="module-constants.html">constants</a>
</li>
<li>
<a href="module-devRoutes.html">devRoutes</a>
</li>
<li>
<a href="module-events.html">events</a>
</li>
<li>
<a href="module-extensions.html">extensions</a>
</li>
<li>
<a href="module-extstreamsInstances.html">extstreamsInstances</a>
</li>
<li>
<a href="module-jiveutil.html">jiveutil</a>
</li>
<li>
<a href="module-oauthRoutes.html">oauthRoutes</a>
</li>
<li>
<a href="module-request.html">request</a>
</li>
<li>
<a href="module-security.html">security</a>
</li>
<li>
<a href="module-service.html">service</a>
</li>
<li>
<a href="module-tasks.html">tasks</a>
</li>
<li>
<a href="module-tileInstances.html">tileInstances</a>
</li>
<li>
<a href="module-tileRoutes.html">tileRoutes</a>
</li>
<li>
<a href="module-tilesDefinitions.html">tilesDefinitions</a>
</li>
<li>
<a href="module-webhooks.html">webhooks</a>
</li>
</ul>
</li>
<li class="dropdown">
<a href="classes.list.html" class="dropdown-toggle" data-toggle="dropdown">Classes<b
class="caret"></b></a>
<ul class="dropdown-menu ">
<li>
<a href="extstreamsDefinitions.html">extstreamsDefinitions</a>
</li>
<li>
<a href="filePersistence.html">filePersistence</a>
</li>
<li>
<a href="memoryPersistence.html">memoryPersistence</a>
</li>
<li>
<a href="memoryScheduler.html">memoryScheduler</a>
</li>
<li>
<a href="oauthHandler.html">oauthHandler</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<div id="main">
<h1 class="page-title">Source: jive-sdk-service/lib/definitionSetup.js</h1>
<section>
<article>
<pre class="sunlight-highlight-javascript linenums">/*
* Copyright 2013 Jive Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var fs = require('fs'),
q = require('q'),
path = require('path'),
jive = require('../api'),
service = require('./service');
var express = require('express');
var consolidate = require('consolidate');
var baseSetup = require('./baseSetup');
var definitionSetup = Object.create(baseSetup);
module.exports = definitionSetup;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Private
function isValidFile(file ) {
return !(file.indexOf('.') == 0)
}
function fsexists(path) {
var deferred = q.defer();
var method = fs.exists ? fs.exists : require('path').exists;
method( path, function(exists ) {
deferred.resolve(exists);
});
return deferred.promise;
}
var tileLifeCycleEvents = [
jive.constants.globalEventNames.NEW_INSTANCE,
jive.constants.globalEventNames.INSTANCE_UPDATED,
jive.constants.globalEventNames.INSTANCE_REMOVED
];
var tileDataPushEvents = [
jive.constants.globalEventNames.DATA_PUSHED,
jive.constants.globalEventNames.ACTIVITY_PUSHED,
jive.constants.globalEventNames.COMMENT_PUSHED
];
function buildHandlerFunction(handlerInfo) {
if ( handlerInfo['globalListener'] ) {
// if explicitly marked as a globalListener, then there are no conditions for handling, just pass it to the
// event handler
return handlerInfo['handler'];
} else {
// otherwise its a 'protected' handler
return function(context, event ) {
var definitionName = handlerInfo['definitionName'];
var eventListener;
if ( context['eventListener'] ) {
eventListener = context['eventListener'];
} else if ( event ) {
if ( tileLifeCycleEvents.indexOf(event) > -1 ) {
eventListener = context['name'];
}
if ( tileDataPushEvents.indexOf(event) > -1 ) {
if ( context['theInstance'] ) {
eventListener = context['theInstance']['name'];
}
}
}
if ( !eventListener || eventListener === definitionName ) {
return handlerInfo['handler'](context);
}
}
}
}
function tileDefinitionStupEventListener(handlerInfo, _definitionName, setupContext) {
var definitionJson;
if ( setupContext ) {
definitionJson = setupContext['definitionJson'];
}
var definitionName = definitionJson ? definitionJson['name'] : _definitionName;
handlerInfo['definitionName'] = definitionName;
if (!handlerInfo['event']) {
throw new Error('Event handler "'
+ definitionName + '" must specify an event name.');
}
if (!handlerInfo['handler']) {
throw new Error('Event handler "'
+ definitionName + '" must specify a function handler.');
}
var eventListener = handlerInfo['eventListener'] || definitionName;
if (jive.events.globalEvents.indexOf(handlerInfo['event']) != -1) {
jive.events.registerEventListener(handlerInfo['event'], buildHandlerFunction(handlerInfo) );
} else {
jive.events.registerEventListener( handlerInfo['event'], buildHandlerFunction(handlerInfo), {
'eventListener' : eventListener,
'description' : handlerInfo['description'] || 'Unique to definition'
});
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// public
/**
* Returns a promise when defintion tasks, life cycle events,
* and other things in the service directory have been processed.
* @param definitionName
* @param svcDir
* @return {*}
*/
definitionSetup.setupDefinitionServices = function( app, definitionName, svcDir, definitionJson ) {
/////////////////////////////////////////////////////
// apply definition specific tasks, life cycle events, etc.
var next;
if ( !definitionJson ) {
// set it up
var definitionLocation = require('path').dirname( svcDir ) + '/definition.json';
next = definitionSetup.setupDefinitionMetadata(definitionLocation);
} else {
next = q.resolve(definitionJson);
}
var setupContext = {
'definitionJson' : definitionJson
};
return next.then( function(definition) {
return definitionSetup.setupServices(app, definitionName, svcDir,
tileDefinitionStupEventListener, setupContext );
});
};
/**
* Returns a promise when all the routes have been calculated for a particular definition directory.
*/
definitionSetup.setupDefinitionRoutes = function(app, definitionName, routesPath){
return definitionSetup.setupRoutes( app, definitionName, routesPath );
};
definitionSetup.setupDefinitionMetadata = function(definitionPath) {
// if a definition exists, read it from disk and save it
return fsexists(definitionPath).then( function(exists) {
if ( exists ) {
return q.nfcall( fs.readFile, definitionPath).then( function(data ) {
var definitionDirName = path.basename( path.dirname( definitionPath ) );
var definition = JSON.parse(data);
definition.id = definition.id === '{{{definition_id}}}' ? null : definition.id;
definition['definitionDirName'] = definitionDirName;
return definition;
}).then( function( definition ) {
var apiToUse = definition['style'] === 'ACTIVITY' ? jive.extstreams.definitions : jive.tiles.definitions;
return apiToUse.save(definition);
});
}
});
};
/**
* Returns a promise for detecting when the definition directory has been autowired.
* Assumes that the definintion directory is exactly the same as the definition name, eg.:
*
* /tiles/my-twitter-definition
*
* In this case the definition name is my-twitter-definition.
* @param definitionDir
*/
definitionSetup.setupOneDefinition = function( app, definitionDir, definitionName ) {
return q.nfcall( fs.stat, definitionDir ).then( function( stat ) {
if ( stat.isDirectory() ) {
definitionName = definitionName ||
(definitionDir.substring( definitionDir.lastIndexOf('/') + 1, definitionDir.length ) ); /// xxx todo this might not always work! use path
var definitionPath = definitionDir + '/definition.json';
var routesPath = definitionDir + '/backend/routes';
var servicesPath = definitionDir + '/backend';
app.use( '/' + definitionName, express.static( definitionDir + '/public' ) );
// setup tile public directory
var definitionApp = express();
definitionApp.engine('html', consolidate.mustache);
definitionApp.set('view engine', 'html');
definitionApp.set('views', definitionDir + '/public');
app.use( definitionApp );
// if a definition exists, read it from disk and save it
var definitionPromise = definitionSetup.setupDefinitionMetadata(definitionPath);
// wire up service and routes
return definitionPromise.then( function(definitionJson) {
var promises = [];
promises.push( fsexists(routesPath).then( function(exists) {
if ( exists ) {
return definitionSetup.setupDefinitionRoutes( definitionApp, definitionName, routesPath );
}
}));
promises.push( fsexists(definitionDir).then( function(exists) {
if ( exists ) {
return definitionSetup.setupDefinitionServices( app, definitionName, servicesPath, definitionJson );
}
}));
return q.all(promises);
});
} else {
return q.resolve();
}
}).catch( function(e) {
jive.logger.error("Failed to setup tile at " + definitionName + "; " + e.stack);
process.exit(-1);
});
};
/**
* Autowires each definition discovered in the provided definitions directory.
* @param definitionsRootDir
* @return {*}
*/
definitionSetup.setupAllDefinitions = function( app, definitionsRootDir ) {
return jive.util.fsexists( definitionsRootDir).then( function(exists) {
if ( exists ) {
return q.nfcall(fs.readdir, definitionsRootDir).then(function(dirContents){
return setupDefinitionsSequentially(app,definitionsRootDir, dirContents);
});
} else {
return q.resolve();
}
}).then( function () {
// make sure that all definitions in the db actually still exist
var remove = function(libraryToUse) {
return libraryToUse.findAll().then( function (allDefinitions) {
var proms = [];
allDefinitions.forEach(function (tile) {
var definitionDir = tile['definitionDirName'];
if ( definitionDir ) {
proms.push(
jive.util.fsexists( definitionsRootDir + '/' + definitionDir).then( function(exists) {
return !exists ? libraryToUse.remove( tile['id']) : q.resolve();
})
);
}
return q.resolve();
});
return q.all(proms);
});
};
return remove( jive.tiles.definitions).then( function() {
return remove( jive.extstreams.definitions );
});
});
};
/**
* This will setup tiledefinition persistence by having one tile insert at a time.
* Tested on jive-persistence-postgres and jive-persistence-mongo
* @param app
* @param definitionsRootDir
* @param directoryContents
* @returns {*}
*/
function setupDefinitionsSequentially(app,definitionsRootDir, directoryContents) {
if (directoryContents.length == 0) {
return q.resolve();
} else {
var item = directoryContents.shift();
if (!isValidFile(item)) {
return setupDefinitionsSequentially(app,definitionsRootDir, directoryContents);
}
var dirPath = definitionsRootDir + '/' + item;
return definitionSetup.setupOneDefinition(app, dirPath)
.then(function () {
return setupDefinitionsSequentially(app,definitionsRootDir, directoryContents);
});
}
}
</pre>
</article>
</section>
</div>
<div class="clearfix"></div>
<footer>
<span class="copyright">
Jive Software, Inc
</span>
<br />
<span class="jsdoc-message">
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0-dev</a>
on Wed Jan 22 2014 12:29:37 GMT-0800 (PST) using the <a href="https://github.com/terryweiss/docstrap">DocStrap template</a>.
</span>
</footer>
</div>
<br clear="both">
</div>
</div>
<script src="scripts/sunlight.js"></script>
<script src="scripts/sunlight.javascript.js"></script>
<script src="scripts/sunlight-plugin.doclinks.js"></script>
<script src="scripts/sunlight-plugin.linenumbers.js"></script>
<script src="scripts/sunlight-plugin.menu.js"></script>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/jquery.scrollTo.js"></script>
<script src="scripts/jquery.localScroll.js"></script>
<script src="scripts/bootstrap-dropdown.js"></script>
<script src="scripts/toc.js"></script>
<script> Sunlight.highlightAll({lineNumbers:true, showMenu: true, enableDoclinks :true}); </script>
<script>
$( function () {
$( "#toc" ).toc( {
selectors : "h1,h2,h3,h4",
showAndHide : false,
scrollTo : 60
} );
$( "#toc>ul" ).addClass( "nav nav-pills nav-stacked" );
$( "#main span[id^='toc']" ).addClass( "toc-shim" );
} );
</script>
</body>
</html>