blob: 3e406f5fdf16c939f43dcc55806f95171574278c [file] [log] [blame]
Nils Diewald40996d82015-02-26 22:23:52 +00001package de.ids_mannheim.korap.server;
Nils Diewald32030a62014-09-03 20:16:50 +00002
Nils Diewaldf04e1002014-09-24 22:52:59 +00003import java.util.*;
4import java.io.*;
Marc Kupietzfb6f4d42015-03-06 12:17:09 +01005import java.net.URL;
Nils Diewaldf04e1002014-09-24 22:52:59 +00006
Nils Diewald32030a62014-09-03 20:16:50 +00007import org.glassfish.grizzly.http.server.HttpServer;
8import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
9import org.glassfish.jersey.server.ResourceConfig;
10
Nils Diewaldf6b351c2014-09-04 21:34:05 +000011import org.slf4j.Logger;
12import org.slf4j.LoggerFactory;
Marc Kupietza61d2ba2015-03-20 16:30:26 +010013import java.util.logging.LogManager;
14import org.slf4j.bridge.SLF4JBridgeHandler;
Nils Diewaldf6b351c2014-09-04 21:34:05 +000015
Nils Diewald32030a62014-09-03 20:16:50 +000016import java.net.URI;
Nils Diewaldf04e1002014-09-24 22:52:59 +000017import java.beans.PropertyVetoException;
Nils Diewald32030a62014-09-03 20:16:50 +000018
Nils Diewalda14ecd62015-02-26 21:00:20 +000019import de.ids_mannheim.korap.KrillIndex;
Nils Diewaldf6b351c2014-09-04 21:34:05 +000020import org.apache.lucene.store.MMapDirectory;
21
Nils Diewaldf04e1002014-09-24 22:52:59 +000022import com.mchange.v2.c3p0.*;
Nils Diewaldf6b351c2014-09-04 21:34:05 +000023
Nils Diewald32030a62014-09-03 20:16:50 +000024/**
Marc Kupietza61d2ba2015-03-20 16:30:26 +010025 * Standalone REST-Service for the Krill node.
26 * Reads a property file at <tt>krill.properties</tt>.
27 * Defaults to port <tt>9876</tt> if no information is given,
28 * and an unprotected in-memory SQLite database for collections.
Nils Diewaldbb33da22015-03-04 16:24:25 +000029 *
Nils Diewaldc99ed5b2015-01-21 22:08:53 +000030 * @author diewald
Nils Diewald32030a62014-09-03 20:16:50 +000031 */
Nils Diewald40996d82015-02-26 22:23:52 +000032public class Node {
Nils Diewald32030a62014-09-03 20:16:50 +000033
34 // Base URI the Grizzly HTTP server will listen on
Marc Kupietza61d2ba2015-03-20 16:30:26 +010035 public static String BASE_URI = "http://localhost:9876/";
36 private static String propFile = "krill.properties";
37
Nils Diewaldbb33da22015-03-04 16:24:25 +000038
Nils Diewaldf6b351c2014-09-04 21:34:05 +000039 // Logger
Nils Diewald40996d82015-02-26 22:23:52 +000040 private final static Logger log = LoggerFactory.getLogger(Node.class);
Nils Diewaldf6b351c2014-09-04 21:34:05 +000041
42 // Index
Nils Diewalda14ecd62015-02-26 21:00:20 +000043 private static KrillIndex index;
Marc Kupietza61d2ba2015-03-20 16:30:26 +010044
45 // Database
Nils Diewaldf04e1002014-09-24 22:52:59 +000046 private static ComboPooledDataSource cpds;
Marc Kupietza61d2ba2015-03-20 16:30:26 +010047 private static String path = null;
48 private static String name = "unknown";
Nils Diewaldf04e1002014-09-24 22:52:59 +000049 private static String dbUser, dbPwd;
Marc Kupietza61d2ba2015-03-20 16:30:26 +010050 private static String dbClass = "org.sqlite.JDBC";
51 private static String dbURL = "jdbc:sqlite:";
Nils Diewaldbb33da22015-03-04 16:24:25 +000052
53
Nils Diewald7cbcfe92014-09-22 22:01:51 +000054 /*
Marc Kupietza61d2ba2015-03-20 16:30:26 +010055 * Todo: Close cdps.close() on shutdown.
Nils Diewald7cbcfe92014-09-22 22:01:51 +000056 * see: https://10.0.10.12/trac/korap/browser/KorAP-modules/KorAP-REST/src/main/java/de/ids_mannheim/korap/web/Application.java
57 * https://10.0.10.12/trac/korap/browser/KorAP-modules/KorAP-REST/src/main/java/de/ids_mannheim/korap/web/ShutdownHook.java
58 */
59
Nils Diewald32030a62014-09-03 20:16:50 +000060 /**
Nils Diewaldbbd39a52015-02-23 19:56:57 +000061 * Starts Grizzly HTTP server exposing JAX-RS
62 * resources defined in this application.
Marc Kupietza61d2ba2015-03-20 16:30:26 +010063 * This will load a <tt>krill.properties</tt> property file.
Nils Diewaldbb33da22015-03-04 16:24:25 +000064 *
Nils Diewald32030a62014-09-03 20:16:50 +000065 * @return Grizzly HTTP server.
66 */
Nils Diewaldbb33da22015-03-04 16:24:25 +000067 public static HttpServer startServer () {
Marc Kupietza61d2ba2015-03-20 16:30:26 +010068 _loadResourceProperties();
Nils Diewaldf04e1002014-09-24 22:52:59 +000069
Nils Diewald32030a62014-09-03 20:16:50 +000070 // create a resource config that scans for JAX-RS resources and providers
71 // in de.ids_mannheim.korap.server package
Nils Diewaldbb33da22015-03-04 16:24:25 +000072 final ResourceConfig rc = new ResourceConfig()
margarethab097bac2015-04-15 11:37:02 +020073 .packages("de.ids_mannheim.korap.server");
Nils Diewald32030a62014-09-03 20:16:50 +000074
75 // create and start a new instance of grizzly http server
76 // exposing the Jersey application at BASE_URI
margarethab097bac2015-04-15 11:37:02 +020077 return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI),
78 rc);
Nils Diewaldff6f7662014-09-21 15:08:52 +000079 };
80
margarethab097bac2015-04-15 11:37:02 +020081
Marc Kupietza61d2ba2015-03-20 16:30:26 +010082 /**
83 * Starts Grizzly HTTP server exposing JAX-RS
84 * resources defined in this application.
85 * Mainly used for testing.
86 *
margarethab097bac2015-04-15 11:37:02 +020087 * @param nodeName
88 * The name of the node.
89 * @param indexPath
90 * The path of the Lucene index.
91 *
Marc Kupietza61d2ba2015-03-20 16:30:26 +010092 * @return Grizzly {@link HttpServer} server.
93 */
Nils Diewaldbb33da22015-03-04 16:24:25 +000094 public static HttpServer startServer (String nodeName, String indexPath) {
Marc Kupietza61d2ba2015-03-20 16:30:26 +010095 LogManager.getLogManager().reset();
96 SLF4JBridgeHandler.install();
Nils Diewaldff6f7662014-09-21 15:08:52 +000097
98 // create a resource config that scans for JAX-RS resources and providers
99 // in de.ids_mannheim.korap.server package
Nils Diewaldbb33da22015-03-04 16:24:25 +0000100 final ResourceConfig rc = new ResourceConfig()
101 .packages("de.ids_mannheim.korap.server");
Nils Diewaldff6f7662014-09-21 15:08:52 +0000102
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000103 name = nodeName;
104 path = indexPath;
Nils Diewaldff6f7662014-09-21 15:08:52 +0000105
106 // create and start a new instance of grizzly http server
107 // exposing the Jersey application at BASE_URI
Nils Diewaldbb33da22015-03-04 16:24:25 +0000108 return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI),
109 rc);
Nils Diewaldff6f7662014-09-21 15:08:52 +0000110 };
111
Nils Diewald32030a62014-09-03 20:16:50 +0000112
113 /**
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100114 * Runner method for Krill node.
Nils Diewaldbb33da22015-03-04 16:24:25 +0000115 *
margarethab097bac2015-04-15 11:37:02 +0200116 * @param args
117 * No special arguments required.
Nils Diewald32030a62014-09-03 20:16:50 +0000118 * @throws IOException
119 */
Nils Diewaldbbd39a52015-02-23 19:56:57 +0000120 public static void main (String[] args) throws IOException {
Nils Diewald979b2fe2014-09-29 16:21:41 +0000121
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100122 // WADL available at BASE_URI + application.wadl
123 // Start the server with krill properties or given defaults
Nils Diewald32030a62014-09-03 20:16:50 +0000124 final HttpServer server = startServer();
Nils Diewald2f44c632014-09-29 19:46:55 +0000125
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000126 // Establish shutdown hook
margarethab097bac2015-04-15 11:37:02 +0200127 Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100128
margarethab097bac2015-04-15 11:37:02 +0200129 @Override
130 public void run () {
131 log.info("Stop Server");
132 server.stop();
133 if (cpds != null)
134 cpds.close();
135 };
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100136
margarethab097bac2015-04-15 11:37:02 +0200137 }, "shutdownHook"));
Nils Diewald2f44c632014-09-29 19:46:55 +0000138
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000139 // Start server
140 try {
141 server.start();
142 log.info("You may kill me gently with Ctrl+C");
143 Thread.currentThread().join();
144 }
145 catch (Exception e) {
146 log.error("Unable to start server: {}", e.getLocalizedMessage());
147 };
Nils Diewaldf6b351c2014-09-04 21:34:05 +0000148 };
Nils Diewald32030a62014-09-03 20:16:50 +0000149
Nils Diewaldbb33da22015-03-04 16:24:25 +0000150
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100151 /**
152 * Get the name of the node.
153 * The name is unique in the cluster and should be persistent.
margarethab097bac2015-04-15 11:37:02 +0200154 *
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100155 * @return The unique name of the node.
156 */
Nils Diewaldff6f7662014-09-21 15:08:52 +0000157 public static String getName () {
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000158 return name;
Nils Diewaldff6f7662014-09-21 15:08:52 +0000159 };
160
Nils Diewald979b2fe2014-09-29 16:21:41 +0000161
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100162 /**
163 * Get the URI (incl. port) the node is listening on.
margarethab097bac2015-04-15 11:37:02 +0200164 *
165 * @return The URI the node is listening on.
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100166 */
Nils Diewaldf04e1002014-09-24 22:52:59 +0000167 public static String getListener () {
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000168 return BASE_URI;
Nils Diewaldf04e1002014-09-24 22:52:59 +0000169 };
170
Nils Diewald979b2fe2014-09-29 16:21:41 +0000171
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100172 /**
173 * Shut down the database pool.
174 */
175 public static void closeDBPool () {
176 if (cpds != null)
177 cpds.close();
178 };
179
180
181 /**
182 * Get the associated database pool
183 * for match collection.
margarethab097bac2015-04-15 11:37:02 +0200184 *
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100185 * @return The CPDS {@link ComboPooledDataSource} object.
186 */
Nils Diewaldf04e1002014-09-24 22:52:59 +0000187 public static ComboPooledDataSource getDBPool () {
Nils Diewald979b2fe2014-09-29 16:21:41 +0000188
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000189 // Pool already initiated
190 if (cpds != null)
191 return cpds;
Nils Diewaldbb33da22015-03-04 16:24:25 +0000192
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100193 // Initiate pool
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000194 try {
Nils Diewaldf04e1002014-09-24 22:52:59 +0000195
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000196 // Parameters are defined in the property file
197 cpds = new ComboPooledDataSource();
198 cpds.setDriverClass(dbClass);
199 cpds.setJdbcUrl(dbURL);
200 if (dbUser != null)
201 cpds.setUser(dbUser);
202 if (dbPwd != null)
203 cpds.setPassword(dbPwd);
204 cpds.setMaxStatements(100);
205 return cpds;
206 }
207 catch (PropertyVetoException e) {
208 log.error(e.getLocalizedMessage());
209 };
210 return null;
Nils Diewaldf04e1002014-09-24 22:52:59 +0000211 };
212
213
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100214 /**
215 * Get the associuated {@link KrillIndex}.
margarethab097bac2015-04-15 11:37:02 +0200216 *
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100217 * @return The associated {@link KrillIndex}.
218 */
Nils Diewalda14ecd62015-02-26 21:00:20 +0000219 public static KrillIndex getIndex () {
Nils Diewald979b2fe2014-09-29 16:21:41 +0000220
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000221 // Index already instantiated
222 if (index != null)
223 return index;
Nils Diewaldbb33da22015-03-04 16:24:25 +0000224
225 try {
Nils Diewald979b2fe2014-09-29 16:21:41 +0000226
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000227 // Get a temporary index
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100228 if (path == null) {
229
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000230 // Temporary index
Nils Diewalda14ecd62015-02-26 21:00:20 +0000231 index = new KrillIndex();
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100232 }
Nils Diewaldf6b351c2014-09-04 21:34:05 +0000233
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100234 // Get a MMap directory index
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000235 else {
236 File file = new File(path);
Nils Diewaldff6f7662014-09-21 15:08:52 +0000237
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000238 log.info("Loading index from {}", path);
239 if (!file.exists()) {
240 log.error("Index not found at {}", path);
241 return null;
242 };
Nils Diewaldff6f7662014-09-21 15:08:52 +0000243
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000244 // Set real index
Nils Diewalda14ecd62015-02-26 21:00:20 +0000245 index = new KrillIndex(new MMapDirectory(file));
Nils Diewaldc99ed5b2015-01-21 22:08:53 +0000246 };
247 return index;
248 }
249 catch (IOException e) {
250 log.error("Index not loadable at {}: {}", path, e.getMessage());
251 };
252 return null;
Nils Diewaldf6b351c2014-09-04 21:34:05 +0000253 };
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100254
255
256 // Load properties from file
257 private static Properties _loadProperties (String propFile) {
258 try {
259 InputStream file = new FileInputStream(propFile);
260 Properties prop = new Properties();
261 prop.load(file);
262
263 // Node properties
264 path = prop.getProperty("krill.indexDir", path);
265 name = prop.getProperty("krill.server.name", name);
266 BASE_URI = prop.getProperty("krill.server.baseURI", BASE_URI);
267
268 // Database properties
269 dbUser = prop.getProperty("krill.db.user", dbUser);
270 dbPwd = prop.getProperty("krill.db.pwd", dbPwd);
271 dbClass = prop.getProperty("krill.db.class", dbClass);
272 dbURL = prop.getProperty("krill.db.jdbcURL", dbURL);
273 return prop;
274 }
275 catch (IOException e) {
276 log.error(e.getLocalizedMessage());
277 };
278 return null;
279 };
280
281
282 // Load properties from resource file
283 private static Properties _loadResourceProperties () {
284
285 // Load configuration
286 URL resUrl = Node.class.getClassLoader().getResource(propFile);
287 if (resUrl == null) {
margarethab097bac2015-04-15 11:37:02 +0200288 log.error(
289 "Cannot find {}. Please create it using \"{}.info\" as template.",
290 propFile, propFile);
Marc Kupietza61d2ba2015-03-20 16:30:26 +0100291 return null;
292 };
293
294 return _loadProperties(resUrl.getFile());
295 };
Nils Diewaldf6b351c2014-09-04 21:34:05 +0000296};