JNDI Lookup Failing For Embedded Jetty Server - java

I have an integration test in one of my projects that I want to run against an embedded jetty server. I followed along with the example here: https://www.eclipse.org/jetty/documentation/jetty-9/index.html#jndi-embedded but when I go to actually run my test it fails with the error:
javax.naming.NameNotFoundException: env is not bound; remaining name 'env/jdbc/NavDS'
at org.eclipse.jetty.jndi.NamingContext.getContext(NamingContext.java:241)
at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:491)
at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:491)
at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:505)
at org.eclipse.jetty.jndi.java.javaRootURLContext.lookup(javaRootURLContext.java:101)
at javax.naming.InitialContext.lookup(InitialContext.java:417)
at com.tura.eyerep.test.TestWebServices.setUpBeforeClass(TestWebServices.java:63)
I'm sure there must be a simple mistake I'm making somewhere but I just can't seem to spot it. Can anyone give a suggestion of what I'm doing wrong here?
In my test I'm setting up the server with:
#BeforeClass
public static void setUpBeforeClass() throws Exception {
server = new Server(8080);
ClassList classList = ClassList.setServerDefault(server);
classList.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration", "org.eclipse.jetty.plus.webapp.PlusConfiguration");
WebAppContext context = new WebAppContext();
context.setExtractWAR(false);
context.setDescriptor("src/main/webapp/WEB-INF/web.xml");
context.setResourceBase("src/main/webapp");
context.setConfigurationDiscovered(false);
BasicDataSource ds = null;
ds = new BasicDataSource();
ds.setUrl("jdbc:h2:mem:myDB;create=true;MODE=MSSQLServer;DATABASE_TO_UPPER=FALSE;");
org.eclipse.jetty.plus.jndi.Resource mydatasource = new org.eclipse.jetty.plus.jndi.Resource(context, "jdbc/NavDS",ds);
server.setHandler(context);
server.start();
}
#Test
public void testLookup()
{
InitialContext ctx = new InitialContext();
DataSource myds = (DataSource) ctx.lookup("java:comp/env/jdbc/NavDS");
assertNotNull( myds);
}
In my web.xml I have a resource ref entry:
<resource-ref>
<description>Nav Datasource</description>
<res-ref-name>jdbc/NavDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

Lets cleanup your testcase first.
// meaningless when you have a WAR that is a directory.
context.setExtractWAR(false); // remove this line
// This prevents Servlet 3 behaviors when using Servlet 2.x descriptors
context.setConfigurationDiscovered(false); // Remove this
The error you are getting ...
javax.naming.NameNotFoundException: env is not bound;
remaining name 'env/jdbc/NavDS'
That likely means that a server is still running somewhere, probably forgot to stop/cleanup the previous server instance. (Look at the example junit5 testcase below, for how it deals with non-fixed ports, how to reference a non-fixed port, and how it stops the lifecycle of the server).
Next, be aware of your scopes.
new org.eclipse.jetty.plus.jndi.Resource(context, "jdbc/NavDS",ds);
That will bind the resource entry to jdbc/NavDS on the scope context.
Which means if you look up the resource outside of the WebAppContext scope,
like you do with testLookup() method it will exist at initialContext.lookup("jdbc/NavDS"), and nowhere else, the java:comp/env prefix/tree doesn't even exist to that testLookup() method scope.
Inside of your webapp, such as in a Filter or Servlet, that context specific resource is bound and available at jdbc:comp/env/jdbc/NavDS.
You have 3 typical scopes.
Order
Scope
EnvEntry or Resource first parameter
1
WebApp
new EnvEntry(webappContext, ...) or new Resource(webappContext, ...)
2
Server
new EnvEntry(server, ...) or new Resource(server, ...)
3
JVM
new EnvEntry(null, ...) or new Resource(null, ...)
If the value doesn't exist at the WebApp scope, the Server scope is checked, and then the JVM scope is checked.
Your Server can have a value for the name val/foo and a specific webapp can have a different value for the same name val/foo, simply by how the scopes are defined.
Next, there's the binding in the Servlet spec, you have specify the <resource-ref> and this combined with the declaration at the server side, bound to context means you can access java:comp/env/jdbc/NavDS from your servlet in that specific webapp.
To see this a different way, in code ...
package jetty.jndi;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.List;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.PathResource;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.FragmentConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class WebAppWithJNDITest
{
private static Server server;
private static WebAppContext context;
public static class JndiDumpServlet extends HttpServlet
{
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/plain");
PrintStream out = new PrintStream(resp.getOutputStream(), false, StandardCharsets.UTF_8);
try
{
dumpJndi(out);
}
catch (NamingException e)
{
throw new ServletException(e);
}
}
}
#BeforeAll
public static void startServer() throws Exception
{
server = new Server(0); // let os/jvm pick a port
Configuration.ClassList classList = Configuration.ClassList.setServerDefault(server);
classList.addAfter(FragmentConfiguration.class.getName(),
EnvConfiguration.class.getName(),
PlusConfiguration.class.getName());
context = new WebAppContext();
context.setContextPath("/");
// This directory only has WEB-INF/web.xml
context.setBaseResource(new PathResource(Paths.get("src/main/webroots/jndi-root")));
context.addServlet(JndiDumpServlet.class, "/jndi-dump");
new org.eclipse.jetty.plus.jndi.Resource(null, "val/foo", Integer.valueOf(707));
new org.eclipse.jetty.plus.jndi.Resource(server, "val/foo", Integer.valueOf(808));
new org.eclipse.jetty.plus.jndi.Resource(context, "val/foo", Integer.valueOf(909));
new org.eclipse.jetty.plus.jndi.EnvEntry(null, "entry/foo", Integer.valueOf(440), false);
new org.eclipse.jetty.plus.jndi.EnvEntry(server, "entry/foo", Integer.valueOf(550), false);
new org.eclipse.jetty.plus.jndi.EnvEntry(context, "entry/foo", Integer.valueOf(660), false);
server.setHandler(context);
server.start();
}
#AfterAll
public static void stopServer()
{
LifeCycle.stop(server);
}
public static void dumpJndi(PrintStream out) throws NamingException
{
InitialContext ctx = new InitialContext();
List<String> paths = List.of("val/foo", "entry/foo");
List<String> prefixes = List.of("java:comp/env/", "");
for (String prefix : prefixes)
{
for (String path : paths)
{
try
{
Integer val = (Integer)ctx.lookup(prefix + path);
out.printf("lookup(\"%s%s\") = %s%n", prefix, path, val);
}
catch (NameNotFoundException e)
{
out.printf("lookup(\"%s%s\") = NameNotFound: %s%n", prefix, path, e.getMessage());
}
}
}
}
#Test
public void testLookup() throws NamingException, IOException
{
System.out.println("-- Dump from WebApp Scope");
HttpURLConnection http = (HttpURLConnection)server.getURI().resolve("/jndi-dump").toURL().openConnection();
try (InputStream in = http.getInputStream())
{
String body = IO.toString(in, StandardCharsets.UTF_8);
System.out.println(body);
}
System.out.println("-- Dump from Test scope");
dumpJndi(System.out);
}
}
Contents of src/main/webroot/jndi-root/WEB-INF/web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<resource-ref>
<description>My Foo Resource</description>
<res-ref-name>val/foo</res-ref-name>
<res-type>java.lang.Integer</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
The output looks like ...
2021-10-26 17:05:16.834:INFO:oejs.Server:main: jetty-9.4.44.v20210927; built: 2021-06-30T11:07:22.254Z; git: 526006ecfa3af7f1a27ef3a288e2bef7ea9dd7e8; jvm 11.0.12+7
2021-10-26 17:05:17.012:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext#19932c16{/,file:///home/joakim/code/jetty/junk/src/main/webroots/jndi-root/,AVAILABLE}
2021-10-26 17:05:17.033:INFO:oejs.AbstractConnector:main: Started ServerConnector#212b5695{HTTP/1.1, (http/1.1)}{0.0.0.0:45387}
2021-10-26 17:05:17.034:INFO:oejs.Server:main: Started #816ms
-- Dump from WebApp Scope
lookup("java:comp/env/val/foo") = 909
lookup("java:comp/env/entry/foo") = 660
lookup("val/foo") = 707
lookup("entry/foo") = 440
-- Dump from Test scope
lookup("java:comp/env/val/foo") = NameNotFound: env is not bound
lookup("java:comp/env/entry/foo") = NameNotFound: env is not bound
lookup("val/foo") = 707
lookup("entry/foo") = 440
2021-10-26 17:05:17.209:INFO:oejs.AbstractConnector:main: Stopped ServerConnector#212b5695{HTTP/1.1, (http/1.1)}{0.0.0.0:0}
2021-10-26 17:05:17.210:INFO:oejs.session:main: node0 Stopped scavenging
2021-10-26 17:05:17.214:INFO:oejsh.ContextHandler:main: Stopped o.e.j.w.WebAppContext#19932c16{/,file:///home/joakim/code/jetty/junk/src/main/webroots/jndi-root/,STOPPED}
Hopefully the scope differences are obvious above.
A variation of the above test is now available at the Eclipse Jetty Embedded Cookbook project.
https://github.com/jetty-project/embedded-jetty-cookbook/
Available in 3 different Jetty flavors
Jetty 9.4.x - WebAppContextWithJNDI.java
Jetty 10.0.x - WebAppContextWithJNDI.java
Jetty 11.0.x - WebAppContextWithJNDI.java

Related

In Tomcat 9, can AutoDeploy be turned off programatically

We use tomcat 9 with spring/hibernate. Obviously its a production code and the tomcat manager is not there. For the tomcat hardening we are trying to turn off the "autoDeploy" via code dynamically. We can do that in server.xml as :
<Host appBase="webapps" autoDeploy="false" name="localhost" unpackWARs="true">
Can that be done? Is there a way to do this programatically?
EDIT: Code attempted:
package test.servlet;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.modeler.Registry;
public class TestServlet extends HttpServlet {
ObjectName oname = null;
MBeanServer mBeanServer = null;
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String name = request.getParameter("app");
PrintWriter writer = response.getWriter();
try {
oname = new ObjectName("Catalina:type=Deployer,host=localhost");
mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
if (!isDeployed(name) && !isServiced(name)) {
writer.println("deploying application -> " + name);
addServiced(name);
try {
// Perform new deployment
check(name);
} finally {
removeServiced(name);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void check(String name) throws Exception {
String[] params = { name };
String[] signature = { "java.lang.String" };
mBeanServer.invoke(oname, "check", params, signature);
}
protected void addServiced(String name) throws Exception {
String[] params = { name };
String[] signature = { "java.lang.String" };
mBeanServer.invoke(oname, "addServiced", params, signature);
}
protected boolean isDeployed(String name) throws Exception {
String[] params = { name };
String[] signature = { "java.lang.String" };
Boolean result = (Boolean) mBeanServer.invoke(oname, "isDeployed", params, signature);
return result.booleanValue();
}
protected boolean isServiced(String name) throws Exception {
String[] params = { name };
String[] signature = { "java.lang.String" };
Boolean result = (Boolean) mBeanServer.invoke(oname, "isServiced", params, signature);
return result.booleanValue();
}
protected void removeServiced(String name) throws Exception {
String[] params = { name };
String[] signature = { "java.lang.String" };
mBeanServer.invoke(oname, "removeServiced", params, signature);
}
}
I guess you would have to disable deployOnStartup and autoDeploy both.
Reference from the Tomcat 9 docs for host :
autoDeploy :
This flag value indicates if Tomcat should check periodically for new
or updated web applications while Tomcat is running. If true, Tomcat
periodically checks the appBase and xmlBase directories and deploys
any new web applications or context XML descriptors found. Updated web
applications or context XML descriptors will trigger a reload of the
web application. The flag's value defaults to true.
deployOnStartup : This flag value indicates if web
applications from this host should be automatically deployed when
Tomcat starts. The flag's value defaults to true.
If you disable deployOnStartup and autoDeploy, then you would need to explicitly configure the manager app via a Context element in server.xml and then use it to deploy additional WAR files/directories.
Note : You can disable auto deploy via setting - autodeploy="false" in your server.xml file.
Read more at : Apache Tomcat 9 Configuration Reference
No, it cannot be, as you cannot set autoDeploy="false" from Java code.
The only way to configure this, is to do it in the server.xml.

Spring MVC: UI-Testing with Test WebApplicationContext and embedded Jetty

tldr; How do I deploy from WebApplicationContext in embedded jetty for a simple automatic test case?
What I have:
A spring application (not spring boot) that uses annotation configuration (no web.xml) and is - for production - build (with gradle) to an ear and deployed on wildfly.
What I ultimately want to do:
Have self-contained (in the applications test package) ui-tests, that can easily be executed (without building and deploying) like any of the other unit or integration tests.
What I have done so far:
The easy part: Setup the actual tests with Selenium WebDriver
The hard part: Start an embedded Jetty with a test WebApplicationContext
My code for the embedded Jetty (yes, I will do some refactoring when I get it running):
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import org.apache.tomcat.util.scan.StandardJarScanner;
import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
import org.eclipse.jetty.jsp.JettyJspServlet;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.session.HashSessionIdManager;
import org.eclipse.jetty.server.session.HashSessionManager;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class JettyServerFactory {
private Server server = null;
public Server start(WebApplicationContext context) throws Exception {
if (server == null) {
this.server = new Server(9090);
setupServer(context);
server.start();
//server.join();
}
return server;
}
public void stop() throws Exception {
if (server != null) {
server.stop();
}
}
private void setupServer(WebApplicationContext context) throws Exception {
final ServletContextHandler contextHandler = new ServletContextHandler();
// Since this is a ServletContextHandler we must manually configure JSP support.
enableEmbeddedJspSupport(contextHandler);
// Spring Security
enableSpringSecurity(contextHandler, context);
/*
// TODO: Does not seem to have any effect
// Set reference to actual Spring ApplicationContext
ServletContext servletContext = contextHandler.getServletContext();
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
*/
// Set resource base folder
contextHandler.setBaseResource(getResourceBase());
// Add DispatcherServlet to context
final ServletHolder servletHolder = new ServletHolder("default", new DispatcherServlet(context));
servletHolder.setInitParameter("dirAllowed", "true");
contextHandler.setContextPath("/oauth");
contextHandler.addServlet(servletHolder, "/");
// Add context to server
server.setHandler(contextHandler);
}
private Resource getResourceBase() {
File file = new File("src/website/application.war");
//servletHolder.setInitParameter("resourceBase", getWebRootResourceUri().toASCIIString());
final Resource base = Resource.newResource(file);
return base;
}
/**
* Apply existing securityFilterChain to context
*
* #param contextHandler
* #param context
*/
private void enableSpringSecurity(ServletContextHandler contextHandler, WebApplicationContext context) {
FilterChainProxy filter = (FilterChainProxy) context.getBean("springSecurityFilterChain");
FilterHolder filterHolder = new FilterHolder(filter);
contextHandler.addFilter(filterHolder, "/*", EnumSet.allOf(DispatcherType.class));
server.setSessionIdManager(new HashSessionIdManager());
HashSessionManager manager = new HashSessionManager();
SessionHandler sessions = new SessionHandler(manager);
contextHandler.setHandler(sessions);
}
/**
* Setup JSP Support for ServletContextHandlers.
* <p>
* NOTE: This is not required or appropriate if using a WebAppContext.
* </p>
*
* #param servletContextHandler the ServletContextHandler to configure
* #throws IOException if unable to configure
*/
private void enableEmbeddedJspSupport(ServletContextHandler servletContextHandler) throws IOException {
// Establish Scratch directory for the servlet context (used by JSP compilation)
File tempDir = new File(System.getProperty("java.io.tmpdir"));
File scratchDir = new File(tempDir.toString(), "embedded-jetty-jsp");
if (!scratchDir.exists()) {
if (!scratchDir.mkdirs()) {
throw new IOException("Unable to create scratch directory: " + scratchDir);
}
}
servletContextHandler.setAttribute("javax.servlet.context.tempdir", scratchDir);
// Set Classloader of Context to be sane (needed for JSTL)
// JSP requires a non-System classloader, this simply wraps the
// embedded System classloader in a way that makes it suitable
// for JSP to use
ClassLoader jspClassLoader = new URLClassLoader(new URL[0], this.getClass().getClassLoader());
servletContextHandler.setClassLoader(jspClassLoader);
// Manually call JettyJasperInitializer on context startup
servletContextHandler.addBean(new JspStarter(servletContextHandler));
// Create / Register JSP Servlet (must be named "jsp" per spec)
ServletHolder holderJsp = new ServletHolder("jsp", JettyJspServlet.class);
holderJsp.setInitOrder(0);
holderJsp.setInitParameter("logVerbosityLevel", "DEBUG");
holderJsp.setInitParameter("fork", "false");
holderJsp.setInitParameter("xpoweredBy", "false");
holderJsp.setInitParameter("compilerTargetVM", "1.8");
holderJsp.setInitParameter("compilerSourceVM", "1.8");
holderJsp.setInitParameter("keepgenerated", "true");
servletContextHandler.addServlet(holderJsp, "*.jsp");
}
/**
* JspStarter for embedded ServletContextHandlers
*
* This is added as a bean that is a jetty LifeCycle on the ServletContextHandler. This bean's doStart method will
* be called as the ServletContextHandler starts, and will call the ServletContainerInitializer for the jsp engine.
*
*/
public static class JspStarter extends AbstractLifeCycle
implements ServletContextHandler.ServletContainerInitializerCaller {
JettyJasperInitializer sci;
ServletContextHandler context;
public JspStarter(ServletContextHandler context) {
this.sci = new JettyJasperInitializer();
this.context = context;
this.context.setAttribute("org.apache.tomcat.JarScanner", new StandardJarScanner());
}
#Override
protected void doStart() throws Exception {
ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(context.getClassLoader());
try {
sci.onStartup(null, context.getServletContext());
super.doStart();
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}
}
private URI getWebRootResourceUri() throws FileNotFoundException, URISyntaxException, MalformedURLException {
String WEBROOT_INDEX = "/application.war/";
URL indexUri = this.getClass().getResource(WEBROOT_INDEX);
if (indexUri == null) {
throw new FileNotFoundException("Unable to find resource " + WEBROOT_INDEX);
}
File file = new File("src/website/application.war");
System.out.println(indexUri.toURI());
System.out.println(file.toURI());
System.out.println(file.getAbsolutePath());
return file.toURI();
}
}
The WebApplicationContext for the test case is simply provided somewhat like this:
...
#WebAppConfiguration
public class ATestClass {
#Autowired
WebApplicationContext context;
...
#Before
public void setupTest() throws Exception {
new JettyServerFactory().start(context);
...
}
...
...
Location of the Resource Base:
Resource placement in the project structure
All static resources like css, js and images are in themes
What does work:
Controllers are hit on requests
Spring Security is active
JSPs are found and rendered (thanks to https://github.com/jetty-project/embedded-jetty-jsp)
What does not work:
All other static resources are missing (css, js, images, etc.). Basically everything from themes
So, what are my questions:
How can I make the missing static resources available?
Is there a completely different/better approach to achieve my ultimate goal? The way, to what I have now, was quite rocky and I'm not sure the missing static content is the last of my problems.
I'm happy to provide additional information/code. But, since this is an actual product, I have some limits on that.
Edits:
Picture of the resource structure
Mind that application.war is just a folder, not actually a war
Resource Config
#EnableWebMvc
#Configuration
public class AppWebMvcConfiguration implements WebMvcConfigurer {
...
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/jsp/", ".jsp");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
boolean developmentMode = configuration.getBooleanFromNewconfig(false, "oauth2.developmentMode");
if (USE_VERSIONED_RESOURCES) {
registry.addResourceHandler("/themes/**")
.addResourceLocations("/themes/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
.resourceChain(developmentMode ? false : true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
.addTransformer(new CssLinkResourceTransformer());
} else {
registry.addResourceHandler("/themes/**")
.addResourceLocations("/themes/")
.setCacheControl(CacheControl.noCache());
}
}
...
}
Which case is used for the ResourceHandler doesn't matter. Neither works.

Application with embedded Jetty showing "page not found" if launched as jar

I have an application that uses embedded jetty. When I run this application in Netbeans IDE then I can browse my site # localhost:8080/
When I launch the jar file of my application from command line: java -jar app.jar then browsing localhost:8080/ jetty server says "page not found"
What am I missing here? Can't figure out the problem.
EDIT:
Netbeans project is uploaded to Github
Everything works fine if I run this project in Netbeans.
But when I take the jar file with lib folder and run it in cmd like this: java -jar EmbeddedJettyJspJstl.jar
Then navigating to http://localhost:8080/test I get errors:
org.apache.jasper.JasperException: java.lang.ClassNotFoundException: org.apache.jsp.WEB_002dINF.jstl_jsp
org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application
My JSP page uses JSTL and looks like it is not locating the jstl libraries?
And this is the code that starts the server:
package server;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* #author lkallas
*/
public class JettyServer {
// Resource path pointing to where the WEBROOT is
private static final String WEBROOT = "/webapp/";
private static final Logger logger = LoggerFactory.getLogger(JettyServer.class);
public void start() throws IOException, InterruptedException, URISyntaxException {
Server server = new Server();
// HTTP connector
ServerConnector connector = new ServerConnector(server);
connector.setHost("localhost");
connector.setPort(8080);
connector.setIdleTimeout(30000);
// Set the connector
server.addConnector(connector);
// Setup JMX for web applications
MBeanContainer mbContainer = new MBeanContainer(
ManagementFactory.getPlatformMBeanServer());
server.addBean(mbContainer);
//Setting up web application
WebAppContext webapp = new WebAppContext();
webapp.setAttribute("javax.servlet.context.tempdir", getScratchDir());
webapp.setDescriptor(WEBROOT + "WEB-INF/web.xml");
webapp.setResourceBase(getWebRootResourceUri().toASCIIString());
webapp.setContextPath("/");
webapp.setWar(getWebRootResourceUri().toASCIIString());
webapp.addAliasCheck(new AllowSymLinkAliasChecker());
//For debugging
logger.info("Descriptor file: {}", webapp.getDescriptor());
logger.info("Resource base: {}", getWebRootResourceUri().toASCIIString());
logger.info("WAR location: {}", webapp.getWar());
HandlerList handlerList = new HandlerList();
handlerList.setHandlers(new Handler[]{webapp, new DefaultHandler()});
// This webapp will use jsps and jstl. We need to enable the
// AnnotationConfiguration in order to correctly
// set up the jsp container
Configuration.ClassList classlist = Configuration.ClassList
.setServerDefault(server);
classlist.addBefore(
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
// Set the ContainerIncludeJarPattern so that jetty examines these
// container-path jars for tlds, web-fragments etc.
// If you omit the jar that contains the jstl .tlds, the jsp engine will
// scan for them instead.
webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*/[^/]*taglibs.*\\.jar$");
// A WebAppContext is a ContextHandler as well so it needs to be set to
// the server so it is aware of where to send the appropriate requests.
server.setHandler(handlerList);
try {
server.start();
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
server.dumpStdErr();
}
/**
* Establish Scratch directory for the servlet context (used by JSP
* compilation)
*/
private File getScratchDir() throws IOException {
File tempDir = new File(System.getProperty("java.io.tmpdir"));
File scratchDir = new File(tempDir.toString(), "embedded-jetty");
if (!scratchDir.exists()) {
if (!scratchDir.mkdirs()) {
throw new IOException("Unable to create scratch directory: " + scratchDir);
}
}
return scratchDir;
}
/**
* Get webroot URI.
*
* #return
* #throws FileNotFoundException
* #throws URISyntaxException
*/
private URI getWebRootResourceUri() throws FileNotFoundException, URISyntaxException {
URL indexUri = this.getClass().getResource(WEBROOT);
if (indexUri == null) {
throw new FileNotFoundException("Unable to find resource " + WEBROOT);
}
logger.debug("WEBROOT: {}", indexUri.toURI().toASCIIString());
return indexUri.toURI();
}
}
I have already looked # http://www.eclipse.org/jetty/documentation/current/advanced-embedding.html
There's a number of reasons and causes that could be affecting you.
However you haven't posted any code to help us identify what the specific cause is.
The Jetty Project maintains an example for this setup, btw.
https://github.com/jetty-project/embedded-jetty-uber-jar
Pay attention to your context.setContextPath() (like #Haider-Ali pointed out), and also your context.setBaseResource()
For JSPs in Embedded Jetty you can look at the other example project
https://github.com/jetty-project/embedded-jetty-jsp
Note prior answer about Embedded Jetty and JSP.

how to create datasource using camel?

I have just started learning Apache Camel. I understood the basics of Routes and Components. Now I want to give a try by connecting to Oracle database, reading records from one particular table and write those records to a file using File component. To read from database I assume I need to use JDBC component and give the dataSourceName.
However, I couldn't find any info on how to create a dataSource using camel. All info that I found related to this topic uses Spring DSL examples. I don't use Spring and I just need to test this using simple standalone Java application.
I am using JDK7u25 with Apache Camel 2.12.1.
Can someone please post a sample to read from the oracle table and write to a file?
[EDIT]
After checking several solutions on the web, I came to know about following two approaches:
Camel to run as standalone. Here is my code:
import javax.sql.DataSource;
import org.apache.camel.main.Main;
import org.apache.camel.builder.RouteBuilder;
import org.apache.commons.dbcp.BasicDataSource;
public class JDBCExample {
private Main main;
public static void main(String[] args) throws Exception {
JDBCExample example = new JDBCExample();
example.boot();
}
public void boot() throws Exception {
// create a Main instance
main = new Main();
// enable hangup support so you can press ctrl + c to terminate the JVM
main.enableHangupSupport();
String url = "jdbc:oracle:thin:#MYSERVER:1521:myDB";
DataSource dataSource = setupDataSource(url);
// bind dataSource into the registery
main.bind("myDataSource", dataSource);
// add routes
main.addRouteBuilder(new MyRouteBuilder());
// run until you terminate the JVM
System.out.println("Starting Camel. Use ctrl + c to terminate the JVM.\n");
main.run();
}
class MyRouteBuilder extends RouteBuilder {
public void configure() {
String dst = "C:/Local Disk E/TestData/Destination";
from("direct:myTable")
.setBody(constant("select * from myTable"))
.to("jdbc:myDataSource")
.to("file:" + dst);
}
}
private DataSource setupDataSource(String connectURI) {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
ds.setUsername("sa");
ds.setPassword("devon1");
ds.setUrl(connectURI);
return ds;
}
}
Using the approach mentioned by Claus lbsen. Here is the code again:
import javax.sql.DataSource;
import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.impl.SimpleRegistry;
import org.apache.camel.main.Main;
import org.apache.camel.builder.RouteBuilder;
import org.apache.commons.dbcp.BasicDataSource;
public class JDBCExample {
private Main main;
public static void main(String[] args) throws Exception {
String url = "jdbc:oracle:thin:#MYSERVER:1521:myDB";
DataSource dataSource = setupDataSource(url);
SimpleRegistry reg = new SimpleRegistry() ;
reg.put("myDataSource",dataSource);
CamelContext context = new DefaultCamelContext(reg);
context.addRoutes(new JDBCExample().new MyRouteBuilder());
context.start();
Thread.sleep(5000);
context.stop();
}
class MyRouteBuilder extends RouteBuilder {
public void configure() {
String dst = "C:/Local Disk E/TestData/Destination";
from("direct:myTable")
.setBody(constant("select * from myTable"))
.to("jdbc:myDataSource")
.to("file:" + dst);
}
}
private static DataSource setupDataSource(String connectURI) {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
ds.setUsername("sa");
ds.setPassword("devon1");
ds.setUrl(connectURI);
return ds;
}
}
But in both the cases I am getting below exception:
Caused by: org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: jdbc://myDataSource due to: No component found with scheme: jdbc
at org.apache.camel.impl.DefaultCamelContext.getEndpoint(DefaultCamelContext.java:534)
at org.apache.camel.util.CamelContextHelper.getMandatoryEndpoint(CamelContextHelper.java:63)
at org.apache.camel.model.RouteDefinition.resolveEndpoint(RouteDefinition.java:192)
at org.apache.camel.impl.DefaultRouteContext.resolveEndpoint(DefaultRouteContext.java:106)
at org.apache.camel.impl.DefaultRouteContext.resolveEndpoint(DefaultRouteContext.java:112)
at org.apache.camel.model.SendDefinition.resolveEndpoint(SendDefinition.java:61)
at org.apache.camel.model.SendDefinition.createProcessor(SendDefinition.java:55)
at org.apache.camel.model.ProcessorDefinition.makeProcessor(ProcessorDefinition.java:500)
at org.apache.camel.model.ProcessorDefinition.addRoutes(ProcessorDefinition.java:213)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:909)
... 12 more
[Thread-0] INFO org.apache.camel.main.MainSupport$HangupInterceptor - Received hang up - stopping the main instance.
There is the SQL example which shows how to setup a DataSource
http://camel.apache.org/sql-example.html
Yes that examples using Spring XML. But how you setup the DataSource can be done in Java code also. Then you need to register the DataSource in the Camel Registry.
For example you can use a JndiRegistry or the SimpleRegistry. The latter is easier.
Here is some pseudo code showing the principle, of creating a registry, add your beans into this registry, and then providing the registry to the constructor of DefaultCamelContext.
SimpleRegistry registry = new SimpleRegistry();
// code to create data source here
DateSource ds = ...
registry.put("myDataSource", ds);
CamelContext camel = new DefaultCamelContext(registry);
So silly me! I had not included camel-jdbc-2.12.1.jar in the CLASSPATH. Now above examples work.
Spring was mentioned there just because it is very useful paradigm of working with DB (mainly because of templates introduced by Spring Framework.) Of course you can hook up the standard JDBC connection and implement DAO by yourself - nothing wrong with that.

embedded ApacheDS in my application, it fails on service.startup() -> DefaultSchemaService.getSchemaManager() returns null

I'm trying to run an embedded ApacheDS in my application. After reading: Running Apache DS embedded in my application
and http://directory.apache.org/apacheds/1.5/41-embedding-apacheds-into-an-application.html
Using the last stable version 1.5.7,
this simple example fails when executing "service.startup();"
Exception in thread "main" java.lang.NullPointerException
at org.apache.directory.server.core.schema.DefaultSchemaService.initialize(DefaultSchemaService.java:380)
at org.apache.directory.server.core.DefaultDirectoryService.initialize(DefaultDirectoryService.java:1425)
at org.apache.directory.server.core.DefaultDirectoryService.startup(DefaultDirectoryService.java:907)
at Test3.runServer(Test3.java:41)
at Test3.main(Test3.java:24)
that is, DefaultSchemaService.getSchemaManager() returns null.
source code:
import java.util.Properties;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.apache.directory.server.core.DefaultDirectoryService;
import org.apache.directory.server.core.partition.Partition;
import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
import org.apache.directory.server.ldap.LdapServer;
import org.apache.directory.server.protocol.shared.transport.TcpTransport;
import org.apache.directory.shared.ldap.entry.ServerEntry;
import org.apache.directory.shared.ldap.name.DN;
public class Test3 {
public static void main(String[] args) throws Exception {
runServer();
testClient();
}
static void runServer() throws Exception {
DefaultDirectoryService service = new DefaultDirectoryService();
service.getChangeLog().setEnabled(false);
Partition partition = new JdbmPartition();
partition.setId("apache");
partition.setSuffix("dc=apache,dc=org");
service.addPartition(partition);
LdapServer ldapService = new LdapServer();
ldapService.setTransports(new TcpTransport(1400));
ldapService.setDirectoryService(service);
service.startup();
// Inject the apache root entry if it does not already exist
try {
service.getAdminSession().lookup(partition.getSuffixDn());
} catch (Exception lnnfe) {
DN dnApache = new DN("dc=Apache,dc=Org");
ServerEntry entryApache = service.newEntry(dnApache);
entryApache.add("objectClass", "top", "domain", "extensibleObject");
entryApache.add("dc", "Apache");
service.getAdminSession().add(entryApache);
}
DN dnApache = new DN("dc=Apache,dc=Org");
ServerEntry entryApache = service.newEntry(dnApache);
entryApache.add("objectClass", "top", "domain", "extensibleObject");
entryApache.add("dc", "Apache");
service.getAdminSession().add(entryApache);
ldapService.start();
}
static void testClient() throws NamingException {
Properties p = new Properties();
p.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
p.setProperty(Context.PROVIDER_URL, "ldap://localhost:1400/");
p.setProperty(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
p.setProperty(Context.SECURITY_CREDENTIALS, "secret");
p.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
DirContext rootCtx = new InitialDirContext(p);
DirContext ctx = (DirContext) rootCtx.lookup("dc=apache,dc=org");
SearchControls sc = new SearchControls();
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<SearchResult> searchResults = ctx.search("", "(objectclass=*)", sc);
while (searchResults.hasMoreElements()) {
SearchResult searchResult = searchResults.next();
Attributes attributes = searchResult.getAttributes();
System.out.println("searchResult.attributes: " + attributes) ;
}
}
}
It seems that ApacheDS versions 1.5.x are not backward compatible.
In ApacheDS 1.5.4 the call "service.startup();" works ok (but it fails somewhere else).
Any idea how to make this example work?
this version of ApacheDS needs to explicitely define the working directory:
service.setWorkingDirectory(new File("data"));
I recently face the similar problem, and after long googling, finally find something useful
Example for Embedded Apache Directory using 1.5.7
http://svn.apache.org/repos/asf/directory/documentation/samples/trunk/embedded-sample/src/main/java/org/apache/directory/seserver/EmbeddedADSVer157.java
and also have a look the pom.xml
Pom.xml Example for Embedded Apache Directory using 1.5.7
http://svn.apache.org/repos/asf/directory/documentation/samples/trunk/embedded-sample/pom.xml
Hope is help!

Categories

Resources