Skip to content

Commit 8671d98

Browse files
committed
Enable support for dependency injection
This makes use of JSON-LD based config files using Components.js.
1 parent ce09e31 commit 8671d98

File tree

90 files changed

+2822
-410
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+2822
-410
lines changed

assets/styles/ldf-server.css

+6-2
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ input {
100100
outline: none;
101101
font-size: .95em;
102102
}
103-
fieldset input {
103+
fieldset input:not([type=radio]) {
104104
width: 500px;
105105
color: #be1622;
106106
background-color: transparent;
@@ -195,7 +195,7 @@ ul.quads a {
195195
ul.quads a:last-child {
196196
margin-right: 0;
197197
}
198-
ul.quads li:not(:hover) a:nth-child(4) {
198+
ul.quads li:not(:hover) a.graph {
199199
color: #999999;
200200
}
201201
abbr {
@@ -253,3 +253,7 @@ dd {
253253
margin: 1em 0;
254254
}
255255
}
256+
257+
.searchForm {
258+
display: inline-block;
259+
}

bin/ldf-server

+56-158
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,80 @@
11
#!/usr/bin/env node
2-
/*! @license MIT ©2013-2016 Ruben Verborgh, Ghent University - imec */
2+
/*! @license MIT ©2013-2017 Ruben Verborgh and Ruben Taelman, Ghent University - imec */
33
/* Standalone Linked Data Fragments Server */
44

5-
var _ = require('lodash'),
6-
fs = require('fs'),
7-
path = require('path'),
8-
cluster = require('cluster'),
9-
LinkedDataFragmentsServer = require('../lib/LinkedDataFragmentsServer'),
10-
IndexDatasource = require('../lib/datasources/IndexDatasource'),
11-
ViewCollection = require('../lib/views/ViewCollection.js');
5+
var cluster = require('cluster'),
6+
ComponentsLoader = require('componentsjs').Loader;
127

138
// Parse arguments
149
var args = process.argv.slice(2);
15-
if (args.length < 1 || args.length > 3 || /^--?h(elp)?$/.test(args[0])) {
16-
console.log('usage: server config.json [port [workers]]');
10+
if (args.length < 1 || args.length > 4 || /^--?h(elp)?$/.test(args[0])) {
11+
console.log('usage: server config.json [port [workers [componentConfigUri]]]');
1712
return process.exit(1);
1813
}
19-
var configDefaults = JSON.parse(fs.readFileSync(path.join(__dirname, '../config/config-defaults.json'))),
20-
config = _.defaults(JSON.parse(fs.readFileSync(args[0])), configDefaults),
21-
port = parseInt(args[1], 10) || config.port,
22-
workers = parseInt(args[2], 10) || config.workers,
23-
protocol = config.protocol,
24-
constructors = {};
2514

26-
// Determine protocol
27-
if (!protocol) {
28-
var protocolMatch = (config.baseURL || '').match(/^(\w+):/);
29-
protocol = config.protocol = protocolMatch ? protocolMatch[1] : 'http';
30-
}
15+
var cliPort = parseInt(args[1], 10),
16+
cliWorkers = parseInt(args[2], 10),
17+
configUri = args[3] || 'urn:ldf-server:my';
18+
19+
var loader = new ComponentsLoader({ scanGlobal: true });
20+
loader.registerAvailableModuleResources()
21+
.then(function () {
22+
// Start up a cluster master
23+
if (cluster.isMaster) {
24+
return loader.getConfigConstructorFromUrl(configUri, args[0])
25+
.then(function (constructor) {
26+
return constructor.makeArguments(true).then(function (args) {
27+
startClusterMaster(args[0]);
28+
});
29+
})
30+
.catch(function (e) {
31+
console.error('Config error:');
32+
console.error(e);
33+
process.exit(1);
34+
});
35+
}
36+
else {
37+
return loader.instantiateFromUrl(configUri, args[0])
38+
.then(function (worker) {
39+
worker.run(cliPort);
40+
})
41+
.catch(function (e) {
42+
console.error('Instantiation error:');
43+
console.error(e);
44+
process.exit(1);
45+
});
46+
}
47+
})
48+
.catch(function (e) {
49+
console.error('Component definition error:');
50+
console.error(e);
51+
process.exit(1);
52+
});
53+
54+
function startClusterMaster(config) {
55+
var workers = cliWorkers || config.workers || 1;
3156

32-
// Start up a cluster master
33-
if (cluster.isMaster) {
3457
// Create workers
35-
console.log('Master %d running on %s://localhost:%d/.', process.pid, protocol, port);
58+
console.log('Master %d running.', process.pid);
3659
for (var i = 0; i < workers; i++)
3760
cluster.fork();
3861

3962
// Respawn crashed workers
4063
cluster.on('listening', function (worker) {
4164
worker.once('exit', function (code, signal) {
42-
if (!worker.suicide) {
65+
if (!worker.exitedAfterDisconnect) {
4366
console.log('Worker %d died with %s. Starting new worker.',
44-
worker.process.pid, code || signal);
67+
worker.process.pid, code || signal);
4568
cluster.fork();
4669
}
4770
});
4871
});
4972

73+
// Disconnect from cluster on SIGINT, so that the process can cleanly terminate
74+
process.once('SIGINT', function () {
75+
cluster.disconnect();
76+
});
77+
5078
// Respawn workers one by one when receiving a SIGHUP signal
5179
process.on('SIGHUP', function respawn() {
5280
console.log('Respawning workers of master %d.', process.pid);
@@ -66,7 +94,7 @@ if (cluster.isMaster) {
6694
return newWorker.kill(), respawnNext(); // Dead workers are replaced automatically
6795
worker.once('exit', function () {
6896
console.log('Worker %d replaces killed worker %d.',
69-
newWorker.process.pid, worker.process.pid);
97+
newWorker.process.pid, worker.process.pid);
7098
respawnNext();
7199
});
72100
worker.kill();
@@ -77,7 +105,7 @@ if (cluster.isMaster) {
77105
function abort(code, signal) {
78106
if (!newWorker.suicide) {
79107
console.log('Respawning aborted because worker %d died with %s.',
80-
newWorker.process.pid, code || signal);
108+
newWorker.process.pid, code || signal);
81109
process.addListener('SIGHUP', respawn);
82110
process.removeListener('SIGHUP', respawnPending);
83111
}
@@ -93,133 +121,3 @@ if (cluster.isMaster) {
93121
function respawnPending() { console.log('Respawning already in progress'); }
94122
});
95123
}
96-
// Start up a worker
97-
else {
98-
// Configure preset URLs
99-
var baseURL = config.baseURL = config.baseURL.replace(/\/?$/, '/'),
100-
baseURLRoot = baseURL.match(/^(?:https?:\/\/[^\/]+)?/)[0],
101-
baseURLPath = baseURL.substr(baseURLRoot.length),
102-
blankNodePath = baseURLRoot ? '/.well-known/genid/' : '',
103-
blankNodePrefix = blankNodePath ? baseURLRoot + blankNodePath : 'genid:';
104-
105-
// Create all data sources
106-
var datasources = config.datasources, datasourceBase = baseURLPath.substr(1), dereference = config.dereference;
107-
Object.keys(datasources).forEach(function (datasourceName) {
108-
var datasourceConfig = config.datasources[datasourceName], datasourcePath;
109-
delete datasources[datasourceName];
110-
if (datasourceConfig.enabled !== false) {
111-
try {
112-
// Avoid illegal URI characters in data source path
113-
datasourcePath = datasourceBase + encodeURI(datasourceName);
114-
datasources[datasourcePath] = datasourceConfig;
115-
// Set up blank-node-to-IRI translation, with dereferenceable URLs when possible
116-
datasourceConfig.settings = _.defaults(datasourceConfig.settings || {}, config);
117-
if (!datasourceConfig.settings.blankNodePrefix) {
118-
datasourceConfig.settings.blankNodePrefix = blankNodePrefix + datasourcePath + '/';
119-
if (blankNodePath)
120-
dereference[blankNodePath + datasourcePath + '/'] = datasourcePath;
121-
}
122-
// Create the data source
123-
var datasource = instantiate(datasourceConfig, '../lib/datasources/');
124-
datasource.on('error', datasourceError);
125-
datasourceConfig.datasource = datasource;
126-
datasourceConfig.url = baseURLRoot + '/' + datasourcePath + '#dataset';
127-
datasourceConfig.title = datasourceConfig.title || datasourceName;
128-
}
129-
catch (error) { datasourceError(error); }
130-
function datasourceError(error) {
131-
delete datasources[datasourcePath];
132-
process.stderr.write('WARNING: skipped datasource ' + datasourceName + '. ' + error.message + '\n');
133-
}
134-
}
135-
});
136-
137-
// Create index data source
138-
var indexPath = datasourceBase.replace(/\/$/, '');
139-
datasources[indexPath] = datasources[indexPath] || {
140-
url: baseURLRoot + '/' + indexPath + '#dataset',
141-
hide: true,
142-
role: 'index',
143-
title: 'dataset index',
144-
datasource: new IndexDatasource({ datasources: datasources }),
145-
};
146-
147-
// Set up assets
148-
config.assetsPath = baseURLPath + 'assets/';
149-
150-
// Set up routers, views, and controllers
151-
config.routers = instantiateAll(config.routers, '../lib/routers/');
152-
config.views = new ViewCollection();
153-
config.views.addViews(instantiateAll(findFiles('../lib/views', /\.js$/)));
154-
config.controllers = instantiateAll(config.controllers, '../lib/controllers/');
155-
156-
// Set up logging
157-
var loggingSettings = _.defaults(config.logging, configDefaults.logging);
158-
config.log = console.log;
159-
if (loggingSettings.enabled) {
160-
var accesslog = require('access-log');
161-
config.accesslogger = function (request, response) {
162-
accesslog(request, response, loggingSettings.format, function (logEntry) {
163-
if (loggingSettings.file) {
164-
fs.appendFile(loggingSettings.file, logEntry + '\n', function (error) {
165-
error && process.stderr.write('Error when writing to access log file: ' + error);
166-
});
167-
}
168-
else console.log(logEntry);
169-
});
170-
};
171-
}
172-
173-
// Create server, and start it when all data sources are ready
174-
var server = new LinkedDataFragmentsServer(config),
175-
pending = _.size(datasources);
176-
_.each(datasources, function (settings) {
177-
var ready = _.once(startWhenReady);
178-
settings.datasource.once('initialized', ready);
179-
settings.datasource.once('error', ready);
180-
});
181-
function startWhenReady() {
182-
if (!--pending) {
183-
server.listen(port);
184-
console.log('Worker %d running on %s://localhost:%d/.', process.pid, protocol, port);
185-
}
186-
}
187-
188-
// Terminate gracefully if possible
189-
process.once('SIGINT', function () {
190-
console.log('Stopping worker', process.pid);
191-
server.stop();
192-
process.on('SIGINT', function () { process.exit(1); });
193-
});
194-
}
195-
196-
197-
// Instantiates an object from the given description
198-
function instantiate(description, includePath) {
199-
var type = description.type || description,
200-
typePath = path.join(includePath ? path.resolve(__dirname, includePath) : '', type),
201-
Constructor = constructors[typePath] || (constructors[typePath] = require(typePath)),
202-
extensions = config.extensions && config.extensions[type] || [],
203-
settings = _.defaults(description.settings || {}, {
204-
extensions: extensions.map(function (x) { return instantiate(x, includePath); }),
205-
}, config);
206-
return new Constructor(settings, config);
207-
}
208-
209-
// Instantiates all objects from the given descriptions
210-
function instantiateAll(descriptions, includePath) {
211-
return (_.isArray(descriptions) ? _.map : _.mapValues)(descriptions,
212-
function (description) { return instantiate(description, includePath); });
213-
}
214-
215-
// Recursively finds files in a folder whose name matches the pattern
216-
function findFiles(folder, pattern, includeCurrentFolder) {
217-
folder = path.resolve(__dirname, folder);
218-
return _.flatten(_.compact(fs.readdirSync(folder).map(function (name) {
219-
name = path.join(folder, name);
220-
if (fs.statSync(name).isDirectory())
221-
return findFiles(name, pattern, true);
222-
else if (includeCurrentFolder && pattern.test(name))
223-
return name;
224-
})));
225-
}

components/Controller.jsonld

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"@context": [
3+
"https://linkedsoftwaredependencies.org/bundles/npm/@ldf/core/^1.0.0/components/context.jsonld"
4+
],
5+
"@id": "npmd:@ldf/server",
6+
"components": [
7+
{
8+
"@id": "ldfc:Controller",
9+
"@type": "AbstractClass",
10+
"parameters": [
11+
{
12+
"@id": "ldfc:Controller#prefix",
13+
"inheritValues": {
14+
"@type": "InheritanceValue",
15+
"onParameter": "ldfc:Server#prefix",
16+
"from": "ldfc:Server"
17+
}
18+
},
19+
{
20+
"@id": "ldfc:Controller#datasource",
21+
"inheritValues": {
22+
"@type": "InheritanceValue",
23+
"onParameter": "ldfc:Server#datasource",
24+
"from": "ldfc:Server"
25+
}
26+
},
27+
{
28+
"@id": "ldfc:Controller#viewCollection",
29+
"inheritValues": {
30+
"@type": "InheritanceValue",
31+
"onParameter": "ldfc:Server#viewCollection",
32+
"from": "ldfc:Server"
33+
}
34+
},
35+
{
36+
"@id": "ldfc:Controller#urlData",
37+
"inheritValues": {
38+
"@type": "InheritanceValue",
39+
"onParameter": "ldfc:Server#urlData",
40+
"from": "ldfc:Server"
41+
}
42+
}
43+
],
44+
"constructorArguments": {
45+
"@id": "ldfc:Controller#constructorArgumentsObject",
46+
"fields": [
47+
{
48+
"@id": "ldfc:Server#prefixField"
49+
},
50+
{
51+
"@id": "ldfc:Server#datasourceField"
52+
},
53+
{
54+
"@id": "ldfc:Server#viewField"
55+
},
56+
{
57+
"@id": "ldfc:Server#urlDataField"
58+
}
59+
]
60+
}
61+
}
62+
]
63+
}

0 commit comments

Comments
 (0)