<commit_before>/*!
 * Copyright 2012 Sakai Foundation (SF) Licensed under the
 * Educational Community 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.osedu.org/licenses/ECL-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 express = require('express');
var fs = require('fs');
var connect = require('connect');

var Cassandra = require('oae-util/lib/cassandra');
var log = require('oae-logger').logger('oae');

var Context = require('oae-context').Context;
var PrincipalAPI = require('oae-principals');

var TenantAPI = require('oae-tenants');
var Tenant = require('oae-tenants/lib/model').Tenant;
var User = require('oae-principals/lib/model').User;
var fs = require('fs');
var Time = require('time');

var IO = require('./io');
var configAPI = require('oae-config');
var config = require('../../../config').config;
var Server = require('./server');

var serverTenant = module.exports.serverTenant = new Tenant('global', 'Global Administration', 2000, 'localhost:2000', true, false);

///////////////////////////
// Setting up the server //
///////////////////////////

/**
 * Start OAE and run the global administrative interface on port 2000 by default, as well as execute the application lifecycle of all the
 * OAE modules in the system. This involves setting up the data schema, starting up tenants in the application, and invoking auxilliary
 * initialization procedures in the proper order.
 *
 * When initializing the container, each OAE module that has a lib/init.js file will be required and the export object will be executed
 * directly. The module will have access to the app object with which to bootstrap. The app object is a JSON object that provides:
 *
 * {
 *      config: { ... },        // The static system configuration information, as provided in ./config.js of the application root directory
 *      server: {ExpressServer} // The running express server object that drives the global administration interface
 * }
 * 
 * @param  {Object}     config      Configuration object contain Cassandra config information
 * @param  {Function}   callback    Standard callback function execute when Sakai OAE has finished starting up
 */
module.exports.init = function(config, callback) {
    callback = callback || function() {};

    // Fire up an express server on port 2000 that will hold the
    // global administrator UI.
    Server.setupServer(serverTenant);

    // set up the app object for bootstrap
    var app = {
        config: config,
        server: serverTenant.server
    };

    // set up application-level error handler
    process.on('uncaughtException', function(err) {
        log().error({ err: err }, 'An uncaught exception was raised to the application.');
    });

    _bootstrap(app, function(err) {
        if (err) {
            return callback(err);
        }

        Server.postInitializeServer(serverTenant);
        callback();
    });

    log().info('Starting Sakai OAE');
};

/**
 * Bootstrap the application container. This involves initializing all the OAE modules that are present.
 *
 * @param {Object}          app             The application object that contains all information required to initialize.
 * @param {Function(err)}   callback        The function invoked when bootstrap is complete.
 * @param {Object}          callback.err    An error that occurred, if any.
 */
var _bootstrap = function(app, callback) {
    getAvailableModules(function(modules) {
        if (modules.length) {
            log().info('Starting modules: %s', modules.join(', '));
            // this array will be used as a stack, reverse the order
            modules.reverse();
            _bootstrapModules(modules, app, callback);
        } else {
            callback(new Error('No modules to install, or error aggregating modules.'));
        }
    });
}

/**
 * Bootstrap all the modules given. Order is important, should always bootstrap in the **reverse** order of the array of modules provided.
 *
 * @param {Array<String>}   modules         An array of modules that should be bootstrapped. These need to be located in the ./node_modules directory
 * @param {Object}          app             The application object that contains all the information required to initialize
 * @param {Function(err)}   callback        The function invoked when bootstrap is complete.
 * @Param {Object}          callback.err    An error that occurred, if any
 */
var _bootstrapModules = function(modules, app, callback) {
    if (modules.length === 0) {
        return callback();
    }

    var module = modules.pop();
    var path = "node_modules/" + module + "/lib/init.js";
    var initErr = false;
    IO.pathExists(path, function(exists) {
        if (exists) {
            // initialize the module
            require(module + '/lib/init')(app, function(err) {
                if (err) {
                    return callback(err);
                }
                return _bootstrapModules(modules, app, callback);
            });
        } else {
            return _bootstrapModules(modules, app, callback);
        }
    });
}


/////////////
// Modules //
/////////////

var getAvailableModules = module.exports.getAvailableModules = function(callback) {
    IO.getFileListForFolder("node_modules", function(modules) {
        var finalModules = [];
        var modulePriority = {};

        // aggregate the oae- modules
        for (var i = 0; i < modules.length; i++) {
            var module = modules[i];
            if (module.substring(0, 4) === 'oae-') {
                // determine module priority
                var filename = module + "/package.json";
                var pkg = require(filename);
                if (pkg.oae && pkg.oae.priority) {
                    // found a priority in package.json at oae.priority
                    modulePriority[module] = pkg.oae.priority;
                } else {
                    // no priority found, it goes in last
                    modulePriority[module] = Number.MAX_VALUE;
                }

                finalModules.push(module);
            }
        }

        // order by the startup priority
        finalModules.sort(function(a, b) {
            if (modulePriority[a] === modulePriority[b]) {
                return a < b ? -1 : 1;
            } else {
                return modulePriority[a] - modulePriority[b];
            }
        });

        callback(finalModules);<commit_msg>Revert commit to fall back to alphabetic reorder when no priority is given<commit_after>/*!
 * Copyright 2012 Sakai Foundation (SF) Licensed under the
 * Educational Community 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.osedu.org/licenses/ECL-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 express = require('express');
var fs = require('fs');
var connect = require('connect');

var Cassandra = require('oae-util/lib/cassandra');
var log = require('oae-logger').logger('oae');

var Context = require('oae-context').Context;
var PrincipalAPI = require('oae-principals');

var TenantAPI = require('oae-tenants');
var Tenant = require('oae-tenants/lib/model').Tenant;
var User = require('oae-principals/lib/model').User;
var fs = require('fs');
var Time = require('time');

var IO = require('./io');
var configAPI = require('oae-config');
var config = require('../../../config').config;
var Server = require('./server');

var serverTenant = module.exports.serverTenant = new Tenant('global', 'Global Administration', 2000, 'localhost:2000', true, false);

///////////////////////////
// Setting up the server //
///////////////////////////

/**
 * Start OAE and run the global administrative interface on port 2000 by default, as well as execute the application lifecycle of all the
 * OAE modules in the system. This involves setting up the data schema, starting up tenants in the application, and invoking auxilliary
 * initialization procedures in the proper order.
 *
 * When initializing the container, each OAE module that has a lib/init.js file will be required and the export object will be executed
 * directly. The module will have access to the app object with which to bootstrap. The app object is a JSON object that provides:
 *
 * {
 *      config: { ... },        // The static system configuration information, as provided in ./config.js of the application root directory
 *      server: {ExpressServer} // The running express server object that drives the global administration interface
 * }
 * 
 * @param  {Object}     config      Configuration object contain Cassandra config information
 * @param  {Function}   callback    Standard callback function execute when Sakai OAE has finished starting up
 */
module.exports.init = function(config, callback) {
    callback = callback || function() {};

    // Fire up an express server on port 2000 that will hold the
    // global administrator UI.
    Server.setupServer(serverTenant);

    // set up the app object for bootstrap
    var app = {
        config: config,
        server: serverTenant.server
    };

    // set up application-level error handler
    process.on('uncaughtException', function(err) {
        log().error({ err: err }, 'An uncaught exception was raised to the application.');
    });

    _bootstrap(app, function(err) {
        if (err) {
            return callback(err);
        }

        Server.postInitializeServer(serverTenant);
        callback();
    });

    log().info('Starting Sakai OAE');
};

/**
 * Bootstrap the application container. This involves initializing all the OAE modules that are present.
 *
 * @param {Object}          app             The application object that contains all information required to initialize.
 * @param {Function(err)}   callback        The function invoked when bootstrap is complete.
 * @param {Object}          callback.err    An error that occurred, if any.
 */
var _bootstrap = function(app, callback) {
    getAvailableModules(function(modules) {
        if (modules.length) {
            log().info('Starting modules: %s', modules.join(', '));
            // this array will be used as a stack, reverse the order
            modules.reverse();
            _bootstrapModules(modules, app, callback);
        } else {
            callback(new Error('No modules to install, or error aggregating modules.'));
        }
    });
}

/**
 * Bootstrap all the modules given. Order is important, should always bootstrap in the **reverse** order of the array of modules provided.
 *
 * @param {Array<String>}   modules         An array of modules that should be bootstrapped. These need to be located in the ./node_modules directory
 * @param {Object}          app             The application object that contains all the information required to initialize
 * @param {Function(err)}   callback        The function invoked when bootstrap is complete.
 * @Param {Object}          callback.err    An error that occurred, if any
 */
var _bootstrapModules = function(modules, app, callback) {
    if (modules.length === 0) {
        return callback();
    }

    var module = modules.pop();
    var path = "node_modules/" + module + "/lib/init.js";
    var initErr = false;
    IO.pathExists(path, function(exists) {
        if (exists) {
            // initialize the module
            require(module + '/lib/init')(app, function(err) {
                if (err) {
                    return callback(err);
                }
                return _bootstrapModules(modules, app, callback);
            });
        } else {
            return _bootstrapModules(modules, app, callback);
        }
    });
}


/////////////
// Modules //
/////////////

var getAvailableModules = module.exports.getAvailableModules = function(callback) {
    IO.getFileListForFolder("node_modules", function(modules) {
        var finalModules = [];
        var modulePriority = {};

        // aggregate the oae- modules
        for (var i = 0; i < modules.length; i++) {
            var module = modules[i];
            if (module.substring(0, 4) === 'oae-') {
                // determine module priority
                var filename = module + "/package.json";
                var pkg = require(filename);
                if (pkg.oae && pkg.oae.priority) {
                    // found a priority in package.json at oae.priority
                    modulePriority[module] = pkg.oae.priority;
                } else {
                    // no priority found, it goes in last
                    modulePriority[module] = Number.MAX_VALUE;
                }

                finalModules.push(module);
            }
        }

        // order by the startup priority
        finalModules.sort(function(a, b) {
            return modulePriority[a] - modulePriority[b];
        });

        callback(finalModules);
{'fraction_non_alphanumeric': 0.11450494319020216, 'fraction_numerical': 0.004279179577984358, 'mean_word_length': 2.429041234505439, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5607250', 'n_tokens_mistral': 3456, 'n_tokens_neox': 3339, 'n_words': 1282}