Created
July 10, 2016 11:21
-
-
Save rudaoshi/33f6efeee23a72fe565f8e33af0873a9 to your computer and use it in GitHub Desktop.
Stanford Core NLP Server 模式的多语言版本。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package edu.stanford.nlp.pipeline; | |
import com.sun.net.httpserver.*; | |
import edu.stanford.nlp.io.IOUtils; | |
import edu.stanford.nlp.io.RuntimeIOException; | |
import edu.stanford.nlp.ling.CoreAnnotations; | |
import edu.stanford.nlp.ling.CoreLabel; | |
import edu.stanford.nlp.ling.IndexedWord; | |
import edu.stanford.nlp.ling.tokensregex.SequenceMatchResult; | |
import edu.stanford.nlp.ling.tokensregex.TokenSequenceMatcher; | |
import edu.stanford.nlp.ling.tokensregex.TokenSequencePattern; | |
import edu.stanford.nlp.semgraph.SemanticGraphCoreAnnotations; | |
import edu.stanford.nlp.semgraph.semgrex.SemgrexMatcher; | |
import edu.stanford.nlp.semgraph.semgrex.SemgrexPattern; | |
import edu.stanford.nlp.util.*; | |
import javax.net.ssl.*; | |
import java.io.*; | |
import java.math.BigInteger; | |
import java.net.InetAddress; | |
import java.net.InetSocketAddress; | |
import java.net.URI; | |
import java.net.URLDecoder; | |
import java.security.*; | |
import java.security.cert.CertificateException; | |
import java.util.*; | |
import java.util.concurrent.*; | |
import java.util.function.Consumer; | |
import java.util.function.Predicate; | |
import java.util.stream.Collectors; | |
import edu.stanford.nlp.pipeline.StanfordCoreNLP; | |
import static edu.stanford.nlp.util.logging.Redwood.Util.*; | |
import static java.net.HttpURLConnection.*; | |
/** | |
* This class creates a server that runs a new Java annotator in each thread. | |
* | |
* @author Gabor Angeli | |
* @author Arun Chaganty | |
*/ | |
public class StanfordCoreNLPServerMultiLang implements Runnable { | |
protected HttpServer server; | |
@ArgumentParser.Option(name="port", gloss="The port to run the server on") | |
protected int serverPort = 9000; | |
@ArgumentParser.Option(name="timeout", gloss="The default timeout, in milliseconds") | |
protected int timeoutMilliseconds = 15000; | |
@ArgumentParser.Option(name="strict", gloss="If true, obey strict HTTP standards (e.g., with encoding)") | |
protected boolean strict = false; | |
@ArgumentParser.Option(name="quiet", gloss="If true, don't print to stdout") | |
protected boolean quiet = false; | |
@ArgumentParser.Option(name="ssl", gloss="If true, start the server with an [insecure!] SSL connection") | |
protected boolean ssl = false; | |
protected final String shutdownKey; | |
protected StanfordCoreNLP pipeline; | |
public static int MAX_CHAR_LENGTH = 100000; | |
public Properties props; | |
/** | |
* The thread pool for the HTTP server. | |
*/ | |
private final ExecutorService serverExecutor = Executors.newFixedThreadPool(ArgumentParser.threads); | |
/** | |
* To prevent grossly wasteful over-creation of pipeline objects, cache the last | |
* few we created, until the garbage collector decides we can kill them. | |
*/ | |
// private final WeakHashMap<Properties, StanfordCoreNLP> pipelineCache = new WeakHashMap<>(); | |
/** | |
* An executor to time out CoreNLP execution with. | |
*/ | |
private final ExecutorService corenlpExecutor = Executors.newFixedThreadPool(ArgumentParser.threads); | |
/** | |
* Create a new Stanford CoreNLP Server. | |
* @param port The port to host the server from. | |
* @param timeout The timeout (in milliseconds) for each command. | |
* @param strict If true, conform more strictly to the HTTP spec (e.g., for character encoding). | |
* @throws IOException Thrown from the underlying socket implementation. | |
*/ | |
/*public StanfordCoreNLPServer(int port, int timeout, boolean strict) throws IOException { | |
this(); | |
this.serverPort = port; | |
this.timeoutMilliseconds = timeout; | |
this.strict = strict; | |
}*/ | |
/** | |
* Create a new Stanford CoreNLP Server, with the default parameters | |
* @throws IOException | |
*/ | |
public StanfordCoreNLPServerMultiLang(Properties props) throws IOException { | |
this.props = props; | |
// Generate and write a shutdown key | |
String tmpDir = System.getProperty("java.io.tmpdir"); | |
File tmpFile = new File(tmpDir + File.separator + "corenlp.shutdown"); | |
tmpFile.deleteOnExit(); | |
if (tmpFile.exists()) { | |
if (!tmpFile.delete()) { | |
throw new IllegalStateException("Could not delete shutdown key file"); | |
} | |
} | |
this.shutdownKey = new BigInteger(130, new Random()).toString(32); | |
IOUtils.writeStringToFile(shutdownKey, tmpFile.getPath(), "utf-8"); | |
pipeline = new StanfordCoreNLP(props); | |
} | |
/** | |
* Parse the URL parameters into a map of (key, value) pairs. | |
* | |
* @param uri The URL that was requested. | |
* | |
* @return A map of (key, value) pairs corresponding to the request parameters. | |
* | |
* @throws UnsupportedEncodingException Thrown if we could not decode the URL with utf8. | |
*/ | |
private static Map<String, String> getURLParams(URI uri) throws UnsupportedEncodingException { | |
if (uri.getQuery() != null) { | |
Map<String, String> urlParams = new HashMap<>(); | |
String query = uri.getQuery(); | |
String[] queryFields = query | |
.replaceAll("\\\\&", "___AMP___") | |
.replaceAll("\\\\+", "___PLUS___") | |
.split("&"); | |
for (String queryField : queryFields) { | |
int firstEq = queryField.indexOf('='); | |
// Convention uses "+" for spaces. | |
String key = URLDecoder.decode(queryField.substring(0, firstEq), "utf8").replaceAll("___AMP___", "&").replaceAll("___PLUS___", "+"); | |
String value = URLDecoder.decode(queryField.substring(firstEq + 1), "utf8").replaceAll("___AMP___", "&").replaceAll("___PLUS___", "+"); | |
urlParams.put(key, value); | |
} | |
return urlParams; | |
} else { | |
return Collections.emptyMap(); | |
} | |
} | |
/** | |
* Reads the POST contents of the request and parses it into an Annotation object, ready to be annotated. | |
* This method can also read a serialized document, if the input format is set to be serialized. | |
* | |
* @param props The properties we are annotating with. This is where the input format is retrieved from. | |
* @param httpExchange The exchange we are reading POST data from. | |
* | |
* @return An Annotation representing the read document. | |
* | |
* @throws IOException Thrown if we cannot read the POST data. | |
* @throws ClassNotFoundException Thrown if we cannot load the serializer. | |
*/ | |
private Annotation getDocument(Properties props, HttpExchange httpExchange) throws IOException, ClassNotFoundException { | |
String inputFormat = props.getProperty("inputFormat", "text"); | |
String date = props.getProperty("date"); | |
switch (inputFormat) { | |
case "text": | |
// The default encoding by the HTTP standard is ISO-8859-1, but most | |
// real users of CoreNLP would likely assume UTF-8 by default. | |
String defaultEncoding = this.strict ? "ISO-8859-1" : "UTF-8"; | |
// Get the encoding | |
Headers h = httpExchange.getRequestHeaders(); | |
String encoding; | |
if (h.containsKey("Content-type")) { | |
String[] charsetPair = Arrays.asList(h.getFirst("Content-type").split(";")).stream() | |
.map(x -> x.split("=")) | |
.filter(x -> x.length > 0 && "charset".equals(x[0])) | |
.findFirst().orElse(new String[]{"charset", defaultEncoding}); | |
if (charsetPair.length == 2) { | |
encoding = charsetPair[1]; | |
} else { | |
encoding = defaultEncoding; | |
} | |
} else { | |
encoding = defaultEncoding; | |
} | |
String text = IOUtils.slurpReader(IOUtils.encodedInputStreamReader(httpExchange.getRequestBody(), encoding)); | |
text = URLDecoder.decode(text, encoding).trim(); | |
// TODO(chaganty): URLdecode string. | |
// Read the annotation | |
Annotation annotation = new Annotation(text); | |
// Set the date (if provided) | |
if (date != null) { | |
annotation.set(CoreAnnotations.DocDateAnnotation.class, date); | |
} | |
return annotation; | |
case "serialized": | |
String inputSerializerName = props.getProperty("inputSerializer", ProtobufAnnotationSerializer.class.getName()); | |
AnnotationSerializer serializer = MetaClass.create(inputSerializerName).createInstance(); | |
Pair<Annotation, InputStream> pair = serializer.read(httpExchange.getRequestBody()); | |
return pair.first; | |
default: | |
throw new IOException("Could not parse input format: " + inputFormat); | |
} | |
} | |
/** | |
* Create (or retrieve) a StanfordCoreNLP object corresponding to these properties. | |
* @param props The properties to create the object with. | |
* @return A pipeline parameterized by these properties. | |
*/ | |
/*private StanfordCoreNLP mkStanfordCoreNLP(Properties props) { | |
StanfordCoreNLP impl; | |
synchronized (pipelineCache) { | |
impl = pipelineCache.get(props); | |
if (impl == null) { | |
impl = new StanfordCoreNLP(props); | |
pipelineCache.put(props, impl); | |
} | |
} | |
return impl; | |
}*/ | |
/** | |
* A helper function to respond to a request with an error. | |
* | |
* @param response The description of the error to send to the user. | |
* @param httpExchange The exchange to send the error over. | |
* | |
* @throws IOException Thrown if the HttpExchange cannot communicate the error. | |
*/ | |
private static void respondError(String response, HttpExchange httpExchange) throws IOException { | |
httpExchange.getResponseHeaders().add("Content-type", "text/plain"); | |
httpExchange.sendResponseHeaders(HTTP_INTERNAL_ERROR, response.length()); | |
httpExchange.getResponseBody().write(response.getBytes()); | |
httpExchange.close(); | |
} | |
/** | |
* A helper function to respond to a request with an error specifically indicating | |
* bad input from the user. | |
* | |
* @param response The description of the error to send to the user. | |
* @param httpExchange The exchange to send the error over. | |
* | |
* @throws IOException Thrown if the HttpExchange cannot communicate the error. | |
*/ | |
private static void respondBadInput(String response, HttpExchange httpExchange) throws IOException { | |
httpExchange.getResponseHeaders().add("Content-type", "text/plain"); | |
httpExchange.sendResponseHeaders(HTTP_BAD_REQUEST, response.length()); | |
httpExchange.getResponseBody().write(response.getBytes()); | |
httpExchange.close(); | |
} | |
/** | |
* A helper function to respond to a request with an error stating that the user is not authorized | |
* to make this request. | |
* | |
* @param httpExchange The exchange to send the error over. | |
* | |
* @throws IOException Thrown if the HttpExchange cannot communicate the error. | |
*/ | |
private static void respondUnauthorized(HttpExchange httpExchange) throws IOException { | |
httpExchange.getResponseHeaders().add("Content-type", "application/javascript"); | |
byte[] content = "{\"message\": \"Unauthorized API request\"}".getBytes("utf-8"); | |
httpExchange.sendResponseHeaders(HTTP_UNAUTHORIZED, content.length); | |
httpExchange.getResponseBody().write(content); | |
httpExchange.close(); | |
} | |
/** | |
* A callback object that lets us hook into the result of an annotation request. | |
*/ | |
public static class FinishedRequest { | |
public final Properties props; | |
public final Annotation document; | |
public final Optional<String> tokensregex; | |
public final Optional<String> semgrex; | |
public FinishedRequest(Properties props, Annotation document) { | |
this.props = props; | |
this.document = document; | |
this.tokensregex = Optional.empty(); | |
this.semgrex = Optional.empty(); | |
} | |
public FinishedRequest(Properties props, Annotation document, String tokensregex, String semgrex) { | |
this.props = props; | |
this.document = document; | |
this.tokensregex = Optional.ofNullable(tokensregex); | |
this.semgrex = Optional.ofNullable(semgrex); | |
} | |
} | |
/** | |
* A simple ping test. Responds with pong. | |
*/ | |
protected static class PingHandler implements HttpHandler { | |
@Override | |
public void handle(HttpExchange httpExchange) throws IOException { | |
// Return a simple text message that says pong. | |
httpExchange.getResponseHeaders().set("Content-type", "text/plain"); | |
String response = "pong\n"; | |
httpExchange.sendResponseHeaders(HTTP_OK, response.getBytes().length); | |
httpExchange.getResponseBody().write(response.getBytes()); | |
httpExchange.close(); | |
} | |
} | |
/** | |
* Sending the appropriate shutdown key will gracefully shutdown the server. | |
* This key is, by default, saved into the local file /tmp/corenlp.shutdown on the | |
* machine the server was run from. | |
*/ | |
protected class ShutdownHandler implements HttpHandler { | |
@Override | |
public void handle(HttpExchange httpExchange) throws IOException { | |
Map<String, String> urlParams = getURLParams(httpExchange.getRequestURI()); | |
httpExchange.getResponseHeaders().set("Content-type", "text/plain"); | |
boolean doExit = false; | |
String response = "Invalid shutdown key\n"; | |
if (urlParams.containsKey("key") && urlParams.get("key").equals(shutdownKey)) { | |
response = "Shutdown successful!\n"; | |
doExit = true; | |
} | |
httpExchange.sendResponseHeaders(HTTP_OK, response.getBytes().length); | |
httpExchange.getResponseBody().write(response.getBytes()); | |
httpExchange.close(); | |
if (doExit) { | |
System.exit(0); | |
} | |
} | |
} | |
/** | |
* Serve a file from the filesystem or classpath | |
*/ | |
public static class FileHandler implements HttpHandler { | |
private final String content; | |
public FileHandler(String fileOrClasspath) throws IOException { | |
this.content = IOUtils.slurpReader(IOUtils.readerFromString(fileOrClasspath)); | |
} | |
@Override | |
public void handle(HttpExchange httpExchange) throws IOException { | |
httpExchange.getResponseHeaders().set("Content-type", "text/html"); | |
httpExchange.sendResponseHeaders(HTTP_OK, content.getBytes().length); | |
httpExchange.getResponseBody().write(content.getBytes()); | |
httpExchange.close(); | |
} | |
} | |
/** | |
* The main handler for taking an annotation request, and annotating it. | |
*/ | |
protected class CoreNLPHandler implements HttpHandler { | |
/** | |
* The default properties to use in the absence of anything sent by the client. | |
*/ | |
public final Properties defaultProps; | |
/** | |
* An authenticator to determine if we can perform this API request. | |
*/ | |
private final Predicate<Properties> authenticator; | |
/** | |
* A callback to call when an annotation job has finished. | |
*/ | |
private final Consumer<FinishedRequest> callback; | |
private final FileHandler homepage; | |
private StanfordCoreNLP pipeline; | |
/** | |
* Create a handler for accepting annotation requests. | |
* @param props The properties file to use as the default if none were sent by the client. | |
*/ | |
public CoreNLPHandler(Properties props, | |
StanfordCoreNLP pipeline, | |
Predicate<Properties> authenticator, | |
Consumer<FinishedRequest> callback, | |
FileHandler homepage) { | |
this.defaultProps = props; | |
this.pipeline = pipeline; | |
this.callback = callback; | |
this.authenticator = authenticator; | |
this.homepage = homepage; | |
} | |
/** | |
* Get the response data type to send to the client, based off of the output format requested from | |
* CoreNLP. | |
* | |
* @param props The properties being used by CoreNLP. | |
* @param of The output format being output by CoreNLP. | |
* | |
* @return An identifier for the type of the HTTP response (e.g., 'text/json'). | |
*/ | |
public String getContentType(Properties props, StanfordCoreNLP.OutputFormat of) { | |
switch(of) { | |
case JSON: | |
return "application/json"; | |
case TEXT: | |
case CONLL: | |
return "text/plain"; | |
case XML: | |
return "text/xml"; | |
case SERIALIZED: | |
String outputSerializerName = props.getProperty("outputSerializer"); | |
if (outputSerializerName != null && | |
outputSerializerName.equals(ProtobufAnnotationSerializer.class.getName())) { | |
return "application/x-protobuf"; | |
} | |
//noinspection fallthrough | |
default: | |
return "application/octet-stream"; | |
} | |
} | |
@Override | |
public void handle(HttpExchange httpExchange) throws IOException { | |
// Set common response headers | |
httpExchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*"); | |
// Get sentence. | |
//Properties props; | |
Annotation ann; | |
StanfordCoreNLP.OutputFormat of; | |
try { | |
//props = getProperties(httpExchange); | |
if ("GET".equalsIgnoreCase(httpExchange.getRequestMethod())) { | |
// Handle direct browser connections (i.e., not a POST request). | |
homepage.handle(httpExchange); | |
return; | |
} else { | |
// Handle API request | |
if (authenticator != null && !authenticator.test(props)) { | |
respondUnauthorized(httpExchange); | |
return; | |
} | |
log("[" + httpExchange.getRemoteAddress() + "] API call w/annotators " + props.getProperty("annotators", "<unknown>")); | |
ann = getDocument(props, httpExchange); | |
of = StanfordCoreNLP.OutputFormat.valueOf(props.getProperty("outputFormat", "json").toUpperCase()); | |
String text = ann.get(CoreAnnotations.TextAnnotation.class).replace('\n', ' '); | |
if (!quiet) { | |
System.out.println(text); | |
} | |
if (text.length() > MAX_CHAR_LENGTH) { | |
respondBadInput("Request is too long to be handled by server: " + text.length() + " characters. Max length is " + MAX_CHAR_LENGTH + " characters.", httpExchange); | |
return; | |
} | |
} | |
} catch (Exception e) { | |
e.printStackTrace(); | |
respondError("Could not handle incoming annotation", httpExchange); | |
return; | |
} | |
Future<Annotation> completedAnnotationFuture = null; | |
try { | |
// Annotate | |
completedAnnotationFuture = corenlpExecutor.submit(() -> { | |
pipeline.annotate(ann); | |
return ann; | |
}); | |
Annotation completedAnnotation; | |
try { | |
int timeoutMilliseconds = Integer.parseInt(props.getProperty("timeout", | |
Integer.toString(StanfordCoreNLPServerMultiLang.this.timeoutMilliseconds))); | |
// Check for too long a timeout from an unauthorized source | |
if (timeoutMilliseconds > 15000) { | |
// If two conditions: | |
// (1) The server is running on corenlp.run (i.e., corenlp.stanford.edu) | |
// (2) The request is not coming from a *.stanford.edu" email address | |
// Then force the timeout to be 15 seconds | |
if ("corenlp.stanford.edu".equals(InetAddress.getLocalHost().getHostName()) && | |
!httpExchange.getRemoteAddress().getHostName().toLowerCase().endsWith("stanford.edu")) { | |
timeoutMilliseconds = 15000; | |
} | |
} | |
completedAnnotation = completedAnnotationFuture.get(timeoutMilliseconds, TimeUnit.MILLISECONDS); | |
} catch (NumberFormatException e) { | |
completedAnnotation = completedAnnotationFuture.get(StanfordCoreNLPServerMultiLang.this.timeoutMilliseconds, TimeUnit.MILLISECONDS); | |
} | |
completedAnnotationFuture = null; // No longer any need for the future | |
// Get output | |
ByteArrayOutputStream os = new ByteArrayOutputStream(); | |
AnnotationOutputter.Options options = AnnotationOutputter.getOptions(pipeline); | |
StanfordCoreNLP.createOutputter(props, options).accept(completedAnnotation, os); | |
os.close(); | |
byte[] response = os.toByteArray(); | |
String contentType = getContentType(props, of); | |
if (contentType.equals("application/json") || contentType.startsWith("text/")) { | |
contentType += ";charset=" + options.encoding; | |
} | |
httpExchange.getResponseHeaders().add("Content-type", contentType); | |
httpExchange.getResponseHeaders().add("Content-length", Integer.toString(response.length)); | |
httpExchange.sendResponseHeaders(HTTP_OK, response.length); | |
httpExchange.getResponseBody().write(response); | |
httpExchange.close(); | |
if (completedAnnotation != null && props.getProperty("annotators") != null && !"".equals(props.getProperty("annotators"))) { | |
callback.accept(new FinishedRequest(props, completedAnnotation)); | |
} | |
} catch (TimeoutException e) { | |
// Print the stack trace for debugging | |
e.printStackTrace(); | |
// Return error message. | |
respondError("CoreNLP request timed out. Your document may be too long.", httpExchange); | |
// Cancel the future if it's alive | |
//noinspection ConstantConditions | |
if (completedAnnotationFuture != null) { | |
completedAnnotationFuture.cancel(true); | |
} | |
} catch (Exception e) { | |
// Print the stack trace for debugging | |
e.printStackTrace(); | |
// Return error message. | |
respondError(e.getClass().getName() + ": " + e.getMessage(), httpExchange); | |
// Cancel the future if it's alive | |
//noinspection ConstantConditions | |
if (completedAnnotationFuture != null) { // just in case... | |
completedAnnotationFuture.cancel(true); | |
} | |
} | |
} | |
/** | |
* Parse the parameters of a connection into a CoreNLP properties file that can be passed into | |
* {@link StanfordCoreNLP}, and used in the I/O stages. | |
* | |
* @param httpExchange The http exchange; effectively, the request information. | |
* | |
* @return A {@link Properties} object corresponding to a combination of default and passed properties. | |
* | |
* @throws UnsupportedEncodingException Thrown if we could not decode the key/value pairs with UTF-8. | |
*/ | |
private Properties getProperties(HttpExchange httpExchange) throws UnsupportedEncodingException { | |
//Map<String, String> urlParams = getURLParams(httpExchange.getRequestURI()); | |
// Load the default properties | |
Properties props = new Properties(); | |
defaultProps.entrySet().stream() | |
.forEach(entry -> props.setProperty(entry.getKey().toString(), entry.getValue().toString())); | |
// Add GET parameters as properties | |
/*urlParams.entrySet().stream() | |
.filter(entry -> | |
!"properties".equalsIgnoreCase(entry.getKey()) && | |
!"props".equalsIgnoreCase(entry.getKey())) | |
.forEach(entry -> props.setProperty(entry.getKey(), entry.getValue())); | |
*/ | |
// Try to get more properties from query string. | |
// (get the properties from the URL params) | |
/*Map<String, String> urlProperties = new HashMap<>(); | |
if (urlParams.containsKey("properties")) { | |
urlProperties = StringUtils.decodeMap(URLDecoder.decode(urlParams.get("properties"), "UTF-8")); | |
} else if (urlParams.containsKey("props")) { | |
urlProperties = StringUtils.decodeMap(URLDecoder.decode(urlParams.get("props"), "UTF-8")); | |
} | |
// (tweak the default properties a bit) | |
if (!props.containsKey("coref.md.type")) { | |
// Set coref head to use dependencies | |
props.setProperty("coref.md.type", "dep"); | |
if (urlProperties.containsKey("annotators") && urlProperties.get("annotators") != null && | |
ArrayUtils.contains(urlProperties.get("annotators").split(","), "parse")) { | |
// (case: the properties have a parse annotator -- | |
// we don't have to use the dependency mention finder) | |
props.remove("coref.md.type"); | |
} | |
} | |
// (add new properties on top of the default properties) | |
urlProperties.entrySet() | |
.forEach(entry -> props.setProperty(entry.getKey(), entry.getValue())); | |
// Get the annotators | |
String annotators = props.getProperty("annotators"); | |
if (PropertiesUtils.getBool(props, "enforceRequirements", true)) { | |
annotators = StanfordCoreNLP.ensurePrerequisiteAnnotators(props.getProperty("annotators").split("[, \t]+")); | |
} | |
// Make sure the properties compile | |
props.setProperty("annotators", annotators);*/ | |
return props; | |
} | |
} | |
private static void sendAndGetResponse(HttpExchange httpExchange, byte[] response) throws IOException { | |
if (response.length > 0) { | |
httpExchange.getResponseHeaders().add("Content-type", "application/json"); | |
httpExchange.getResponseHeaders().add("Content-length", Integer.toString(response.length)); | |
httpExchange.sendResponseHeaders(HTTP_OK, response.length); | |
httpExchange.getResponseBody().write(response); | |
httpExchange.close(); | |
} | |
} | |
private HttpsServer addSSLContext(HttpsServer server) { | |
log("Adding SSL context to server"); | |
try { | |
KeyStore ks = KeyStore.getInstance("JKS"); | |
ks.load(IOUtils.getInputStreamFromURLOrClasspathOrFileSystem("edu/stanford/nlp/pipeline/corenlp.jks"), "corenlp".toCharArray()); | |
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); | |
kmf.init(ks, "corenlp".toCharArray()); | |
SSLContext sslContext = SSLContext.getInstance("TLS"); | |
sslContext.init(kmf.getKeyManagers(), null, null); | |
// Add SSL support to the server | |
server.setHttpsConfigurator(new HttpsConfigurator(sslContext) { | |
public void configure(HttpsParameters params) { | |
SSLContext context = getSSLContext(); | |
SSLEngine engine = context.createSSLEngine(); | |
params.setNeedClientAuth(false); | |
params.setCipherSuites(engine.getEnabledCipherSuites()); | |
params.setProtocols(engine.getEnabledProtocols()); | |
params.setSSLParameters(context.getDefaultSSLParameters()); | |
} | |
}); | |
// Return | |
return server; | |
} catch (CertificateException | IOException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
/** | |
* Returns the implementing Http server. | |
*/ | |
public Optional<HttpServer> getServer() { | |
return Optional.ofNullable(server); | |
} | |
/** @see StanfordCoreNLPServer#run(Predicate, Consumer, StanfordCoreNLPServer.FileHandler, boolean) */ | |
@Override | |
public void run() { | |
// Set the static page handler | |
try { | |
FileHandler homepage = new FileHandler("edu/stanford/nlp/pipeline/demo/corenlp-brat.html"); | |
run(req -> true, obj -> {}, homepage, false); | |
} catch (IOException e) { | |
throw new RuntimeIOException(e); | |
} | |
} | |
/** | |
* Run the server. | |
* This method registers the handlers, and initializes the HTTP server. | |
*/ | |
public void run(Predicate<Properties> authenticator, Consumer<FinishedRequest> callback, FileHandler homepage, boolean https) { | |
try { | |
if (https) { | |
server = addSSLContext(HttpsServer.create(new InetSocketAddress(serverPort), 0)); // 0 is the default 'backlog' | |
} else { | |
server = HttpServer.create(new InetSocketAddress(serverPort), 0); // 0 is the default 'backlog' | |
} | |
server.createContext("/", new CoreNLPHandler(props, pipeline, authenticator, callback, homepage)); | |
server.createContext("/corenlp-brat.js", new FileHandler("edu/stanford/nlp/pipeline/demo/corenlp-brat.js")); | |
server.createContext("/corenlp-brat.cs", new FileHandler("edu/stanford/nlp/pipeline/demo/corenlp-brat.css")); | |
server.createContext("/ping", new PingHandler()); | |
server.createContext("/shutdown", new ShutdownHandler()); | |
server.setExecutor(serverExecutor); | |
server.start(); | |
log("StanfordCoreNLPServer listening at " + server.getAddress()); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
/** | |
* The main method. | |
* Read the command line arguments and run the server. | |
* | |
* @param args The command line arguments | |
* | |
* @throws IOException Thrown if we could not start / run the server. | |
*/ | |
public static void main(String[] args) throws IOException { | |
FileHandler homepage; | |
try { | |
homepage = new FileHandler("edu/stanford/nlp/pipeline/demo/corenlp-brat.html"); | |
} catch (IOException e) { | |
throw new RuntimeIOException(e); | |
} | |
Properties props = null; | |
// this was taken directly from edu.stanford.nlp.pipeline.StanfordCoreNLP.main | |
props = StringUtils.argsToProperties(args); | |
// if (!props.containsKey("props")) | |
// { | |
// error("props must be provided"); | |
// return; | |
// } | |
// Run the server | |
log("Starting server..."); | |
StanfordCoreNLPServerMultiLang server = new StanfordCoreNLPServerMultiLang(props); | |
ArgumentParser.fillOptions(server, args); | |
if (server.ssl) { | |
server.run(req -> true, res -> {}, homepage, true); | |
} else { | |
server.run(req -> true, res -> {}, homepage, false); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment