summaryrefslogtreecommitdiffstats
path: root/sample-apps/http-api-using-request-handlers-and-processors
diff options
context:
space:
mode:
authorKristian Aune <kraune@yahoo-inc.com>2017-06-13 09:38:59 +0200
committerKristian Aune <kraune@yahoo-inc.com>2017-06-13 09:38:59 +0200
commit11b568c2dbec5f9fa35ab8a0aee98dd485db5230 (patch)
tree57c97f04fb900f0b5d44e6f1a7e12112eea7371b /sample-apps/http-api-using-request-handlers-and-processors
parent344730820bb8e6f23eb0784a0dd4b469657ab49e (diff)
add HTTP API sample app
Diffstat (limited to 'sample-apps/http-api-using-request-handlers-and-processors')
-rw-r--r--sample-apps/http-api-using-request-handlers-and-processors/README.md4
-rw-r--r--sample-apps/http-api-using-request-handlers-and-processors/pom.xml85
-rw-r--r--sample-apps/http-api-using-request-handlers-and-processors/src/main/application/services.xml25
-rw-r--r--sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/AnnotatingProcessor.java97
-rw-r--r--sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DataProcessor.java87
-rw-r--r--sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DemoComponent.java47
-rw-r--r--sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DemoHandler.java76
-rw-r--r--sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DemoRenderer.java119
-rw-r--r--sample-apps/http-api-using-request-handlers-and-processors/src/main/resources/configdefinitions/demo.def5
-rw-r--r--sample-apps/http-api-using-request-handlers-and-processors/src/test/java/com/yahoo/example/ApplicationMain.java27
10 files changed, 572 insertions, 0 deletions
diff --git a/sample-apps/http-api-using-request-handlers-and-processors/README.md b/sample-apps/http-api-using-request-handlers-and-processors/README.md
new file mode 100644
index 00000000000..570ebf62015
--- /dev/null
+++ b/sample-apps/http-api-using-request-handlers-and-processors/README.md
@@ -0,0 +1,4 @@
+# Vespa sample applications - Building a HTTP API using request handlers and processors
+
+Refer to the [http-api-tutorial.html](https://git.corp.yahoo.com/pages/vespa/documentation/documentation/jdisc/http-api-tutorial.html) for documentation
+
diff --git a/sample-apps/http-api-using-request-handlers-and-processors/pom.xml b/sample-apps/http-api-using-request-handlers-and-processors/pom.xml
new file mode 100644
index 00000000000..7ae8549c385
--- /dev/null
+++ b/sample-apps/http-api-using-request-handlers-and-processors/pom.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0"?>
+<!-- Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+ http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.yahoo.demo</groupId>
+ <artifactId>sample-app</artifactId>
+ <version>1.0.1</version>
+ <packaging>container-plugin</packaging> <!-- Use Vespa packaging -->
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <test.hide>true</test.hide>
+ <vespa_version>6-SNAPSHOT</vespa_version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>application</artifactId> <!-- Is this needed? -->
+ <version>${vespa_version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>container-dev</artifactId> <!-- not container-dev -->
+ <version>${vespa_version}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.6.1</version>
+ <configuration>
+ <optimize>true</optimize>
+ <showDeprecation>true</showDeprecation>
+ <showWarnings>true</showWarnings>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.19.1</version>
+ <configuration>
+ <systemPropertyVariables>
+ <isMavenSurefirePlugin>true</isMavenSurefirePlugin>
+ </systemPropertyVariables>
+ <redirectTestOutputToFile>${test.hide}</redirectTestOutputToFile>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>vespa-application-maven-plugin</artifactId> <!-- Zip the application package -->
+ <version>${vespa_version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>packageApplication</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>bundle-plugin</artifactId>
+ <version>${vespa_version}</version>
+ <extensions>true</extensions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/sample-apps/http-api-using-request-handlers-and-processors/src/main/application/services.xml b/sample-apps/http-api-using-request-handlers-and-processors/src/main/application/services.xml
new file mode 100644
index 00000000000..add155c2279
--- /dev/null
+++ b/sample-apps/http-api-using-request-handlers-and-processors/src/main/application/services.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
+<services version="1.0">
+ <container id="default" version="1.0">
+ <processing>
+ <chain id="default">
+ <processor id="com.yahoo.demo.AnnotatingProcessor" bundle="demo">
+ <config name="demo.demo">
+ <demo>
+ <item>
+ <term>smurf</term>
+ </item>
+ </demo>
+ </config>
+ </processor>
+ <processor id="com.yahoo.demo.DataProcessor" bundle="demo" />
+ </chain>
+ <renderer id="demo" class="com.yahoo.demo.DemoRenderer" bundle="demo" />
+ </processing>
+ <handler id="com.yahoo.demo.DemoHandler" bundle="demo">
+ <binding>http://*/demo</binding>
+ </handler>
+ <component id="com.yahoo.demo.DemoComponent" bundle="demo"/>
+ </container>
+</services>
diff --git a/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/AnnotatingProcessor.java b/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/AnnotatingProcessor.java
new file mode 100644
index 00000000000..e241d59f5d7
--- /dev/null
+++ b/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/AnnotatingProcessor.java
@@ -0,0 +1,97 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.demo;
+
+import com.google.common.base.Splitter;
+import com.yahoo.processing.Processor;
+import com.yahoo.processing.Request;
+import com.yahoo.processing.Response;
+import com.yahoo.processing.execution.Execution;
+import com.yahoo.processing.request.CompoundName;
+import com.yahoo.processing.request.ErrorMessage;
+import com.yahoo.processing.response.DataList;
+import com.yahoo.yolean.chain.Before;
+import com.yahoo.yolean.chain.Provides;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A processor which processes the incoming query property "terms", then checks
+ * whether there are any smurfs, i.e. DemoData instances containing the string
+ * {@link DemoComponent#SMURF}, and adds errors if that is the case.
+ */
+@Provides(AnnotatingProcessor.DemoProperty.NAME)
+@Before(DataProcessor.DemoData.NAME)
+public class AnnotatingProcessor extends Processor {
+
+ public static class DemoProperty {
+
+ public static final String NAME = "demo.property";
+ public static final CompoundName NAME_AS_COMPOUND = new CompoundName(NAME);
+
+ private final List<String> terms = new ArrayList<>();
+
+ public void add(String term) {
+ terms.add(term);
+ }
+
+ public List<String> terms() {
+ return terms;
+ }
+ }
+
+ private final DemoConfig defaultTermSet;
+
+ public final CompoundName TERMS = new CompoundName("terms");
+
+ private static final Splitter splitter = Splitter.on(' ').omitEmptyStrings();
+
+ public AnnotatingProcessor(DemoConfig defaultTermSet) {
+ this.defaultTermSet = defaultTermSet;
+ }
+
+ @Override
+ public Response process(Request request, Execution execution) {
+ Response response;
+ List<?> d;
+ DemoProperty p = new DemoProperty();
+ String terms = request.properties().getString(TERMS);
+
+ if (terms != null) {
+ for (String s : splitter.split(terms)) {
+ p.add(s);
+ }
+ } else {
+ for (DemoConfig.Demo demo : defaultTermSet.demo()) {
+ p.add(demo.term());
+ }
+ }
+ request.properties().set(DemoProperty.NAME_AS_COMPOUND, p);
+ response = execution.process(request);
+ d = response.data().asList();
+ traverse(d, response.data().request().errors());
+ return response;
+ }
+
+ private boolean traverse(List<?> list, List<ErrorMessage> topLevelErrors) {
+ boolean smurfFound = false;
+ // traverse the tree in the response, and react to the known types
+ for (Object data : list) {
+ if (data instanceof DataList) {
+ smurfFound = traverse(((DataList<?>) data).asList(),
+ topLevelErrors);
+ } else if (data instanceof DataProcessor.DemoData) {
+ DataProcessor.DemoData content = (DataProcessor.DemoData) data;
+ if (DemoComponent.SMURF.equals(content.content())) {
+ topLevelErrors.add(new ErrorMessage("There's a smurf!"));
+ smurfFound = true;
+ }
+ }
+ if (smurfFound) {
+ break;
+ }
+ }
+ return smurfFound;
+ }
+
+} \ No newline at end of file
diff --git a/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DataProcessor.java b/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DataProcessor.java
new file mode 100644
index 00000000000..915beb38f5e
--- /dev/null
+++ b/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DataProcessor.java
@@ -0,0 +1,87 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.demo;
+
+import com.yahoo.component.provider.ListenableFreezableClass;
+import com.yahoo.processing.Processor;
+import com.yahoo.processing.Request;
+import com.yahoo.processing.Response;
+import com.yahoo.processing.execution.Execution;
+import com.yahoo.processing.response.ArrayDataList;
+import com.yahoo.processing.response.Data;
+import com.yahoo.processing.response.DataList;
+import com.yahoo.yolean.chain.After;
+import com.yahoo.yolean.chain.Provides;
+
+/**
+ * A processor making a nested result sets of "normalized" strings from the
+ * request property {@link AnnotatingProcessor.DemoProperty#NAME}.
+ */
+@Provides(DataProcessor.DemoData.NAME)
+@After(AnnotatingProcessor.DemoProperty.NAME)
+public class DataProcessor extends Processor {
+ public static class DemoData extends ListenableFreezableClass implements Data {
+ public static final String NAME = "DemoData";
+
+ private final Request request;
+ private final String content;
+
+ DemoData(Request request, String content) {
+ this.request = request;
+ this.content = content;
+ }
+
+ @Override
+ public Request request() {
+ return request;
+ }
+
+ public String content() {
+ return content;
+ }
+
+ public String toString() {
+ return NAME + "(\"" + content + "\")";
+ }
+ }
+
+ private final DemoComponent termChecker;
+
+ public DataProcessor(DemoComponent termChecker) {
+ this.termChecker = termChecker;
+ }
+
+ @Override
+ public Response process(Request request, Execution execution) {
+ Response r = new Response(request);
+ @SuppressWarnings("unchecked")
+ DataList<Data> current = r.data();
+ DataList<Data> previous = null;
+ String exampleProperty = request.properties().getString(DemoHandler.REQUEST_URI);
+ Object o = request.properties().get(AnnotatingProcessor.DemoProperty.NAME_AS_COMPOUND);
+
+
+ if (exampleProperty != null) {
+ current.add(new DemoData(request, exampleProperty));
+ }
+
+ if (o instanceof AnnotatingProcessor.DemoProperty) {
+ // create a nested result set with a level for each term
+ for (String s : ((AnnotatingProcessor.DemoProperty) o).terms()) {
+ String normalized = termChecker.normalize(s);
+ DemoData data = new DemoData(request, normalized);
+
+ if (current == null) {
+ current = ArrayDataList.create(request);
+ }
+ current.add(data);
+ if (previous != null) {
+ previous.add(current);
+ }
+ previous = current;
+ current = null;
+ }
+ }
+ return r;
+ }
+
+} \ No newline at end of file
diff --git a/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DemoComponent.java b/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DemoComponent.java
new file mode 100644
index 00000000000..455784525e1
--- /dev/null
+++ b/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DemoComponent.java
@@ -0,0 +1,47 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.demo;
+
+import com.yahoo.component.AbstractComponent;
+
+import java.text.Normalizer;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+
+/**
+ * A shared component with an "expensive" constructor exposing a shared,
+ * thread-safe service.
+ */
+public class DemoComponent extends AbstractComponent {
+ public static final String SMURF = "smurf";
+
+ private final Set<Integer> illegalHashes;
+
+ public DemoComponent() {
+ illegalHashes = new HashSet<Integer>();
+ Random r = new Random();
+ // generate up to 1e6 unique hashes
+ for (int i = 0; i < 1000 * 1000; ++i) {
+ illegalHashes.add(r.nextInt());
+ }
+ }
+
+ /**
+ * NFKC-normalize term, or replace it with "smurf" with a low probability.
+ * Will change choice for each run, but will be constant in a single run of
+ * the container.
+ *
+ * @param term
+ * term to normalize or replace with "smurf"
+ * @return NFKC-normalized term or "smurf"
+ */
+ public String normalize(String term) {
+ String normalized = Normalizer.normalize(term, Normalizer.Form.NFKC);
+ if (illegalHashes.contains(normalized.hashCode())) {
+ return SMURF;
+ } else {
+ return normalized;
+ }
+ }
+
+}
diff --git a/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DemoHandler.java b/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DemoHandler.java
new file mode 100644
index 00000000000..b7ceab55609
--- /dev/null
+++ b/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DemoHandler.java
@@ -0,0 +1,76 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.demo;
+
+import com.google.inject.Inject;
+import com.yahoo.container.jdisc.HttpRequest;
+import com.yahoo.container.jdisc.HttpResponse;
+import com.yahoo.container.jdisc.ThreadedHttpRequestHandler;
+import com.yahoo.jdisc.handler.ContentChannel;
+import com.yahoo.processing.handler.ProcessingHandler;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Annotate an incoming request with the URI string used to query from the
+ * network, and pass the request on to the processing handler.
+ */
+public class DemoHandler extends ThreadedHttpRequestHandler {
+
+ /** The name used by the processing handler to choose output renderer. */
+ private static final String FORMAT = "format";
+
+ /** The property name for the incoming URI as a string. */
+ public static final String REQUEST_URI = "request.uri";
+
+ private final ProcessingHandler processingHandler;
+
+ /**
+ * Constructor for use in injection. The requested objects are subclasses of
+ * component or have dedicated providers, so the container will know how to
+ * create this handler.
+ *
+ * @param executor
+ * threadpool, provided by the container
+ * @param processingHandler
+ * the processing handler, also automatically injected
+ */
+ @Inject
+ public DemoHandler(Executor executor, ProcessingHandler processingHandler) {
+ super(executor, null, true);
+ this.processingHandler = processingHandler;
+ }
+
+ @Override
+ public HttpResponse handle(HttpRequest request) {
+ // We have implemented #handle(HttpRequest, ContentChannel) to be
+ // able to use the ProcessingHandler, so this will never be called.
+ // An implementation is needed, though, as the method is abstract.
+ throw new UnsupportedOperationException("See #handle(HttpRequest, ContentChannel)");
+ }
+
+ @Override
+ public HttpResponse handle(HttpRequest request, ContentChannel channel) {
+ HttpRequest.Builder builder =
+ new HttpRequest.Builder(request).put(REQUEST_URI, request.getUri().toString());
+ setFormat(builder, request);
+ return processingHandler.handle(builder.createDirectRequest(),
+ channel);
+ }
+
+ /**
+ * Set the output format to the renderer with id = "demo" in services.xml if
+ * no explicit format parameter is present. This allows using e.g. the
+ * default processing renderer by adding <code>&amp;format=default</code> to
+ * the HTTP request.
+ *
+ * @param builder
+ * the mutable builder instance used for creating the forwarding request
+ * @param request
+ * the incoming HTTP request
+ */
+ private void setFormat(HttpRequest.Builder builder, HttpRequest request) {
+ if ( ! request.hasProperty(FORMAT)) {
+ builder.put(FORMAT, "demo");
+ }
+ }
+}
diff --git a/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DemoRenderer.java b/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DemoRenderer.java
new file mode 100644
index 00000000000..c30adbcf7aa
--- /dev/null
+++ b/sample-apps/http-api-using-request-handlers-and-processors/src/main/java/com/yahoo/demo/DemoRenderer.java
@@ -0,0 +1,119 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.demo;
+
+import com.yahoo.processing.Response;
+import com.yahoo.processing.rendering.AsynchronousSectionedRenderer;
+import com.yahoo.processing.response.Data;
+import com.yahoo.processing.response.DataList;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Render a response as plain text. First line is whether an error occurred,
+ * second rendering initialization time stamp, then each line is response data
+ * (indented according to its place in the hierarchic response), and the last
+ * line is time stamp for when the renderer was finished.
+ */
+public class DemoRenderer extends AsynchronousSectionedRenderer<Response> {
+
+ /**
+ * Indent size for rendering hierarchic response data.
+ */
+ public static final int INDENT_SIZE = 4;
+
+ // Response heading
+ private String heading;
+
+ // Just a utility to write strings to output stream
+ private Writer writer;
+
+ // current indent in the rendered tree
+ String indent;
+
+ /**
+ * No global, shared state to set.
+ */
+ public DemoRenderer() {
+ }
+
+ @Override
+ public void beginResponse(OutputStream stream) throws IOException {
+ writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8.newEncoder());
+ if (getResponse().data().request().errors().size() == 0) {
+ writer.write("OK\n");
+ } else {
+ writer.write("Oops!\n");
+ }
+ writer.write(heading);
+ writer.write('\n');
+ }
+
+ /**
+ * Indent {@link #INDENT_SIZE} spaces for each level in the tree.
+ */
+ @Override
+ public void beginList(DataList<?> list) throws IOException {
+ indent = spaces((getRecursionLevel() - 1) * INDENT_SIZE);
+ }
+
+ @Override
+ public void data(Data data) throws IOException {
+ if (!(data instanceof DataProcessor.DemoData)) {
+ return;
+ }
+ writer.write(indent);
+ writer.write(((DataProcessor.DemoData) data).content());
+ writer.write('\n');
+ }
+
+ private static String spaces(int len) {
+ StringBuilder s = new StringBuilder(len);
+ for (int i = 0; i < len; ++i) {
+ s.append(' ');
+ }
+ return s.toString();
+ }
+
+ /**
+ * Out-dent one level if not at outermost level.
+ */
+ @Override
+ public void endList(DataList<?> list) throws IOException {
+ if (indent.length() == 0) {
+ return;
+ }
+ indent = spaces(indent.length() - INDENT_SIZE);
+ }
+
+ @Override
+ public void endResponse() throws IOException {
+ writer.write("Rendering finished work: " + System.currentTimeMillis());
+ writer.write('\n');
+ writer.close();
+ }
+
+ @Override
+ public String getEncoding() {
+ return StandardCharsets.UTF_8.name();
+ }
+
+ @Override
+ public String getMimeType() {
+ return "text/plain";
+ }
+
+ /**
+ * Initialize mutable, per-result set state here.
+ */
+ @Override
+ public void init() {
+ long time = System.currentTimeMillis();
+
+ super.init(); // Important! The base class needs to initialize itself.
+ heading = "Renderer initialized: " + time;
+ }
+}
diff --git a/sample-apps/http-api-using-request-handlers-and-processors/src/main/resources/configdefinitions/demo.def b/sample-apps/http-api-using-request-handlers-and-processors/src/main/resources/configdefinitions/demo.def
new file mode 100644
index 00000000000..9a804089433
--- /dev/null
+++ b/sample-apps/http-api-using-request-handlers-and-processors/src/main/resources/configdefinitions/demo.def
@@ -0,0 +1,5 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+namespace=demo
+
+demo[].term string
+
diff --git a/sample-apps/http-api-using-request-handlers-and-processors/src/test/java/com/yahoo/example/ApplicationMain.java b/sample-apps/http-api-using-request-handlers-and-processors/src/test/java/com/yahoo/example/ApplicationMain.java
new file mode 100644
index 00000000000..da85e486602
--- /dev/null
+++ b/sample-apps/http-api-using-request-handlers-and-processors/src/test/java/com/yahoo/example/ApplicationMain.java
@@ -0,0 +1,27 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.example;
+
+import com.yahoo.application.Networking;
+import org.junit.Test;
+
+import java.nio.file.FileSystems;
+
+import static org.junit.Assume.assumeTrue;
+
+public class ApplicationMain {
+
+ @Test
+ public void runFromMaven() throws Exception {
+ assumeTrue(Boolean.valueOf(System.getProperty("isMavenSurefirePlugin")));
+ main(null);
+ }
+
+ public static void main(String[] args) throws Exception {
+ try (com.yahoo.application.Application app = com.yahoo.application.Application.fromApplicationPackage(
+ FileSystems.getDefault().getPath("src/main/application"),
+ Networking.enable)) {
+ app.getClass(); // throws NullPointerException
+ Thread.sleep(Long.MAX_VALUE);
+ }
+ }
+} \ No newline at end of file