/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomee.embedded;
import org.apache.openejb.loader.IO;
import org.apache.openejb.loader.JarLocation;
import org.apache.openejb.util.NetworkUtil;
import org.junit.Rule;
import org.junit.Test;
import javax.ejb.EJB;
import javax.ejb.Singleton;
import javax.inject.Inject;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import javax.websocket.server.ServerEndpoint;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.security.Principal;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static javax.xml.bind.DatatypeConverter.printBase64Binary;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
public class ClasspathAsWebappTest {
@Inject
private MyBean bean;
@EJB
private Task2 anEjb;
@Rule
public final ThreadStackRule debugWatcher = new ThreadStackRule();
@Test
public void run() throws MalformedURLException {
MyInitializer.found = null;
MyBean.VALUE = null;
try (final Container container = new Container(
new Configuration()
.http(NetworkUtil.getNextAvailablePort())
.property("openejb.container.additional.exclude", "org.apache.tomee.embedded.")
.property("openejb.additional.include", "tomee-")
.user("tomee", "tomeepwd")
.loginConfig(new LoginConfigBuilder().basic())
.securityConstaint(new SecurityConstaintBuilder().addAuthRole("**").authConstraint(true).addCollection("api", "/api/resource2/")))
.deployPathsAsWebapp(JarLocation.jarLocation(MyInitializer.class))
.inject(this)) {
// Servlet (initializer, servlet)
assertNotNull(MyInitializer.found);
final Iterator<Class<?>> it = MyInitializer.found.iterator();
while (it.hasNext()) { // ThreadStackRule defines one for instance
final Class<?> next = it.next();
if (next.getEnclosingClass() != null && !Modifier.isStatic(next.getModifiers())) {
it.remove();
}
}
assertEquals(1, MyInitializer.found.size());
assertEquals(Task1.class, MyInitializer.found.iterator().next());
try {
assertEquals("Servlet!", IO.slurp(new URL("http://localhost:" + container.getConfiguration().getHttpPort() + "/s")));
} catch (final IOException e) {
fail(e.getMessage());
}
try {
assertEquals("WebServlet", IO.slurp(new URL("http://localhost:" + container.getConfiguration().getHttpPort() + "/w")));
} catch (final IOException e) {
fail(e.getMessage());
}
// JSP
try {
assertEquals("JSP", IO.slurp(new URL("http://localhost:" + container.getConfiguration().getHttpPort() + "/?test=JSP")).trim());
} catch (final IOException e) {
fail(e.getMessage());
}
// CDI
assertNotNull(bean);
assertNull(bean.value());
MyBean.VALUE = "cdi";
assertEquals("cdi", bean.value());
// EJB
MyBean.VALUE = "ejb";
assertEquals("ejb", anEjb.run());
// JAXRS
try {
assertEquals("jaxrs", IO.slurp(new URL("http://localhost:" + container.getConfiguration().getHttpPort() + "/api/resource")));
} catch (final IOException e) {
fail(e.getMessage());
}
// JAXRS + servlet security
try {
final URL url = new URL("http://localhost:" + container.getConfiguration().getHttpPort() + "/api/resource2/");
final HttpURLConnection c = HttpURLConnection.class.cast(url.openConnection());
c.setRequestProperty("Authorization", "Basic " + printBase64Binary("tomee:tomeepwd".getBytes()));
assertEquals("tomee", IO.slurp(c.getInputStream()));
c.disconnect();
} catch (final IOException e) {
fail(e.getMessage());
}
try {
assertEquals("tomee", IO.slurp(new URL("http://tomee:tomeepwd@localhost:" + container.getConfiguration().getHttpPort() + "/api/resource2/")));
fail("should have been not authorized");
} catch (final IOException e) {
// ok
}
// WebSocket
final WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer();
try {
WebSocketClient.message = null;
final WebSocketClient webSocketClient = new WebSocketClient();
final Session session = webSocketContainer.connectToServer(webSocketClient, new URI("ws://localhost:" + container.getConfiguration().getHttpPort() + "/ws"));
webSocketClient.latch.await(20, TimeUnit.SECONDS);
session.close();
assertEquals("websocket", WebSocketClient.message);
} catch (final Exception e) {
fail(e.getMessage());
}
}
}
@ClientEndpoint
public static class WebSocketClient {
private static String message;
private final CountDownLatch latch = new CountDownLatch(1);
@OnMessage
public void onMessage(final String msg) {
message = msg;
latch.countDown();
}
}
@ServerEndpoint("/ws")
public static class WebSocketEndpoint {
@OnOpen
public void open(final Session session) {
try {
session.getBasicRemote().sendText("websocket");
} catch (IOException e) {
try {
session.close(new CloseReason(CloseReason.CloseCodes.PROTOCOL_ERROR, "Should be able to send a message"));
} catch (final IOException e1) {
throw new IllegalStateException(e1);
}
}
}
}
@ApplicationPath("api")
public static class App extends Application {
}
@Path("resource")
public static class Resource {
@GET
public String t() {
return "jaxrs";
}
}
@Path("resource2")
public static class Secured {
@Context
private SecurityContext sc;
@GET
public String t() {
final Principal principal = sc.getUserPrincipal();
return principal.getName();
}
}
@WebServlet(urlPatterns = "/w")
public static class MyWebServlet extends HttpServlet {
@Override
protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("WebServlet");
}
}
@HandlesTypes(Runnable.class)
public static class MyInitializer implements ServletContainerInitializer {
private static Set<Class<?>> found;
@Override
public void onStartup(final Set<Class<?>> c, final ServletContext ctx) throws ServletException {
found = c;
ctx.addServlet("s", new HttpServlet() {
@Override
protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Servlet!");
}
}).addMapping("/s");
}
}
public static class Task1 implements Runnable {
@Override
public void run() {
// no-op
}
}
@Singleton
public static class Task2 {
public String run() {
return MyBean.VALUE;
}
}
public static class MyBean {
private static volatile String VALUE;
public String value() {
return VALUE;
}
}
}