├── .gitignore
├── web
├── index.html
└── WEB-INF
│ └── web.xml
├── lib
├── embed
│ ├── guava-15.0.jar
│ └── jetty-all-9.1.0.v20131115.jar
├── compile
│ └── servlet-api-3.1.jar
└── runtime
│ ├── slf4j-api-1.7.5.jar
│ ├── slf4j-simple-1.7.5.jar
│ └── minimal-json-0.9.2-SNAPSHOT.jar
├── .project
├── .classpath
├── src
├── java
│ └── mypackage
│ │ └── HelloworldServlet.java
└── embed-src
│ └── mypackage
│ └── WebAppUnassembled.java
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | build
3 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 | This is static resource!
--------------------------------------------------------------------------------
/lib/embed/guava-15.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ferdynice/helloworld-war/HEAD/lib/embed/guava-15.0.jar
--------------------------------------------------------------------------------
/lib/compile/servlet-api-3.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ferdynice/helloworld-war/HEAD/lib/compile/servlet-api-3.1.jar
--------------------------------------------------------------------------------
/lib/runtime/slf4j-api-1.7.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ferdynice/helloworld-war/HEAD/lib/runtime/slf4j-api-1.7.5.jar
--------------------------------------------------------------------------------
/lib/runtime/slf4j-simple-1.7.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ferdynice/helloworld-war/HEAD/lib/runtime/slf4j-simple-1.7.5.jar
--------------------------------------------------------------------------------
/lib/embed/jetty-all-9.1.0.v20131115.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ferdynice/helloworld-war/HEAD/lib/embed/jetty-all-9.1.0.v20131115.jar
--------------------------------------------------------------------------------
/lib/runtime/minimal-json-0.9.2-SNAPSHOT.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ferdynice/helloworld-war/HEAD/lib/runtime/minimal-json-0.9.2-SNAPSHOT.jar
--------------------------------------------------------------------------------
/web/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | index.html
9 |
10 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | helloworld-war
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/java/mypackage/HelloworldServlet.java:
--------------------------------------------------------------------------------
1 | package mypackage;
2 |
3 | import java.io.IOException;
4 |
5 | import javax.servlet.annotation.WebServlet;
6 | import javax.servlet.http.HttpServlet;
7 | import javax.servlet.http.HttpServletRequest;
8 | import javax.servlet.http.HttpServletResponse;
9 |
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import com.eclipsesource.json.JsonObject;
14 |
15 | @WebServlet("/helloworld/*")
16 | public class HelloworldServlet extends HttpServlet {
17 | private static final long serialVersionUID = -7759593256585062849L;
18 | private static final Logger LOG = LoggerFactory.getLogger(HelloworldServlet.class);
19 |
20 | @Override
21 | public void doGet(HttpServletRequest req, HttpServletResponse resp)
22 | throws IOException {
23 | LOG.info("serving request");
24 | if ("json".equals(req.getParameter("format"))) {
25 | LOG.info("special format for request {}", req);
26 | resp.setContentType("application/json");
27 | String json = new JsonObject().add("msg", "Hello!").toString();
28 | resp.getWriter().print(json);
29 | } else {
30 | resp.setContentType("text/plain");
31 | resp.getWriter().println("Hello, world");
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Helloworld WAR
2 |
3 | ### A example Java WAR project / template project
4 |
5 | Contains:
6 | - Helloworld servlet (using Annotations)
7 | - an example static html file
8 | - a most basic web.xml
9 | - compile time servlet-api.jar (so doesn't need Java EE)
10 | - Ant build.xml that builds the WAR
11 | - Simple logging, with slf4j-api and sl4j-simple
12 | - Jetty embedded server for running directly in Eclipe
13 |
14 | It should work with Java 6, 7 and upwards.
15 | It doesn't contain any dependendency injection specific frameworks,
16 | such as Spring or Guice. (Although you can add this easily).
17 |
18 | The nature is an Eclipse project,
19 | it contains a minimal .classpath and .project file.
20 |
21 | #### Building the WAR
22 | To build a WAR that you can deploy (for example to Tomcat or Jetty),
23 | you can run 'ant' from the project root.
24 | By default the Java source and target version is **1.7**,
25 | this can be changed in the build.xml file.
26 |
27 | The WAR is tested to work with Apache Tomcat 7 and Jettyrunner 9.
28 |
29 | #### Running in Eclipse
30 | Typically, during development, you want run the application directly
31 | in Eclipse, for quick results and easy debugging.
32 | (Including working breakpoints and hot code swap).
33 |
34 | This is possible thanks to embedding Jetty.
35 | For this, run 'WebAppUnassembled' as a Java application.
36 |
37 | Note that it is not trivial to dynamically load the annotated servlets this way.
38 | (Most examples around the web involve around creating a war file, which defeat some purposes).
39 | However WebAppUnassembled tries a best effort to do this by using Classpath scanning,
40 | still picking up the essential annotations with basic options.
41 | The annotations are WebServlet, WebFilter and WebListener.
42 |
43 | It uses the Google Guava helper library, which is a nice utility to have anyway.
44 | (If you want to call it from within your web app itself, move the library to lib/runtime
45 | or it won't be included in the war file when you build it).
46 |
47 | #### LICENSE
48 | Licensed under [Eclipse Public License](http://www.eclipse.org/legal/epl-v10.html).
49 |
50 |
--------------------------------------------------------------------------------
/src/embed-src/mypackage/WebAppUnassembled.java:
--------------------------------------------------------------------------------
1 | package mypackage;
2 | import java.util.Arrays;
3 | import java.util.EnumSet;
4 | import java.util.EventListener;
5 |
6 | import javax.servlet.DispatcherType;
7 | import javax.servlet.Filter;
8 | import javax.servlet.annotation.WebFilter;
9 | import javax.servlet.annotation.WebListener;
10 | import javax.servlet.annotation.WebServlet;
11 | import javax.servlet.http.HttpServlet;
12 |
13 | import org.eclipse.jetty.server.Server;
14 | import org.eclipse.jetty.servlet.FilterHolder;
15 | import org.eclipse.jetty.servlet.ServletHolder;
16 | import org.eclipse.jetty.webapp.WebAppContext;
17 |
18 | import com.google.common.collect.ObjectArrays;
19 | import com.google.common.reflect.ClassPath;
20 |
21 | public class WebAppUnassembled
22 | {
23 | static {
24 | //this will log to to standard out instead of standard err.
25 | System.setProperty("org.slf4j.simpleLogger.logFile", "System.out");
26 | //have nice datetime stamps in the log lines
27 | System.setProperty("org.slf4j.simpleLogger.showDateTime", "true");
28 | System.setProperty("org.slf4j.simpleLogger.dateTimeFormat", "yyyy-MM-dd HH:mm:ss.SSS");
29 | }
30 |
31 | public static void main(String[] args) throws Exception
32 | {
33 | Server server = new Server(8080);
34 |
35 | WebAppContext context = new WebAppContext();
36 |
37 | context.setResourceBase("./web");
38 | loadAnnotations(context);
39 | server.setHandler(context);
40 |
41 | server.start();
42 | server.join();
43 | }
44 |
45 |
46 |
47 | private static void loadAnnotations(WebAppContext context) throws Exception {
48 | // Add annotations from classpath, using only file resources
49 | // (thus using only classes from this project's src folder).
50 | // NOTE: This mimics the annotation behaviour of loading a WAR,
51 | // but it is certainly not fully functional
52 | // (some annotations and/or annotate elements are not implemented).
53 | ClassPath classpath = ClassPath.from(WebAppUnassembled.class
54 | .getClassLoader());
55 | for (ClassPath.ClassInfo classInfo : classpath.getTopLevelClasses()) {
56 | if (classInfo.url().toString().startsWith("file:")) {
57 | String cname = classInfo.getName();
58 | Class> type = Class.forName(cname);
59 |
60 | WebServlet servletAnn = type.getAnnotation(WebServlet.class);
61 | if (servletAnn != null) {
62 | for (String pattern : ObjectArrays.concat(
63 | servletAnn.value(), servletAnn.urlPatterns(),
64 | String.class)) {
65 | System.out.println("pattern:" + pattern + " servlet:"
66 | + cname);
67 | context.addServlet(new ServletHolder((HttpServlet) type
68 | .getConstructor().newInstance()), pattern);
69 | }
70 | }
71 |
72 | WebFilter filterAnn = type.getAnnotation(WebFilter.class);
73 | if (filterAnn != null) {
74 | for (String pattern : ObjectArrays.concat(
75 | filterAnn.value(), filterAnn.urlPatterns(),
76 | String.class)) {
77 | System.out.println("pattern:" + pattern + " filter:"
78 | + cname);
79 | DispatcherType[] disTypes = filterAnn.dispatcherTypes();
80 | EnumSet dispatches = EnumSet
81 | .copyOf(Arrays.asList(disTypes));
82 | context.addFilter(new FilterHolder((Filter) type
83 | .getConstructor().newInstance()), pattern,
84 | dispatches);
85 | }
86 | }
87 |
88 | WebListener listenAnn = type.getAnnotation(WebListener.class);
89 | if (listenAnn != null) {
90 | System.out.println("listener:" + cname);
91 | context.addEventListener((EventListener) type
92 | .getConstructor().newInstance());
93 | }
94 | }
95 | }
96 | }
97 |
98 | }
--------------------------------------------------------------------------------