Embedded Jetty: Different ports for internally- and externally-visible endpoints? - java

I've got a REST app that uses embedded Jetty as the server. Most of the endpoints need to be publicly-visible (and have appropriate authentication built in), but a few are for internal-use only. I'd like to avoid the overhead of authentication on those and instead use the firewall to restrict access:
Externally-visible endpoints are served on port 10000, which the external firewall leaves open.
Internally-visible endpoints are served on port 20000, which the external firewall blocks.
However, I can't figure out how to achieve this with embedded Jetty. I've tried instantiating two Server objects, one on port 10000 with the appropriate servlet handlers registered and one on port 20000 with the appropriate servlet handlers registered. However, only the server instance that is started second works; requests to endpoints hosted by the one started first result in 404 responses.
The Jetty documentation talks about how to do this with *.xml configurations , but not for an embedded instance.
Any thoughts or ideas? Or is there a better way to achieve the internal/external endpoint isolation I'm after? The hard requirement is that both internal and external endpoints need to "run" in the same JVM.
Edit
Turns out that the problem was related to using Guice and the Guice-servlets extension (issues 618 and 635). Running two embedded Jetty instances works fine as described in James Kingsbery's answer below.
Guice uses a filter (GuiceFilter) registered with server context to get ahold of requests that need request-scoped dependency injection (DI) and to construct servlets and filters that require DI. Unfortunately, it uses a static object to manage the list of servlets and filters associated with it.
In a typical setup, the guice-servlet.jar containing GuiceFilter is included per-application and thus loaded by a different classloader for each application--- and everything works fine. No so with embedded Jetty, where essentially everything is loaded by the default system classloader.
Solution to Guice Problem
The latest master (commit fbbb52dcc92e) of Guice contains an updated GuiceFilter with support for a dynamic reference to the FilterPipeline object (the static object causing the problems). Unfortunately, the constructor to inject the FilterPipeline instance is package-private. So, to use it you need to create a wrapper class in the com.google.inject.servlet package that exposes that constructor:
package com.google.inject.servlet;
import com.google.inject.Inject;
public class NonStaticGuiceFilter extends GuiceFilter {
/**
* Do not use. Must inject a {#link FilterPipeline} via the constructor.
*/
#SuppressWarnings("unused")
private NonStaticGuiceFilter() {
throw new IllegalStateException();
}
#Inject
public NonStaticGuiceFilter(FilterPipeline filterPipeline) {
super(filterPipeline);
}
}
To use this class, create an instance using the injector with your ServletModule installed and register it with your Jetty Context:
// Create the context handler
ServletContextHandler handler = new ServletContextHandler(myServer, "/context");
// Create the injector, registering your ServletModule
final Injector injector = Guice.createInjector(new MyServletModule());
// Add the Guice listener for this injector
handler.addEventListener(new GuiceServletContextListener() {
#Override
protected Injector getInjector() {
return injector;
}
});
// Filter all requests through Guice via NonStaticGuiceFilter.
// Guice will construct the FilterPipeline instance needed by
// NonStaticGuiceFilter.
handler.addFilter(
new FilterHolder(injector
.getInstance(NonStaticGuiceFilter.class)), "/*", null);

My usual crutch in getting started with an embedded Jetty project is the Wicket maven archetype. Here is a class based on that archetype that should do pretty much what you need:
package net.kingsbery;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.bio.SocketConnector;
import org.mortbay.jetty.webapp.WebAppContext;
public class Start {
public static void main(String[] args) throws Exception {
Server server = new Server();
SocketConnector connector = new SocketConnector();
// Set some timeout options to make debugging easier.
connector.setMaxIdleTime(1000 * 60 * 60);
connector.setSoLingerTime(-1);
connector.setPort(10080);
server.setConnectors(new Connector[] { connector });
WebAppContext bb = new WebAppContext();
bb.setServer(server);
bb.setContextPath("/");
bb.setWar("src/main/secret-webapp");
server.addHandler(bb);
Server server2 = new Server();
SocketConnector connector2 = new SocketConnector();
// Set some timeout options to make debugging easier.
connector2.setMaxIdleTime(1000 * 60 * 60);
connector2.setSoLingerTime(-1);
connector2.setPort(20000);
server2.setConnectors(new Connector[] { connector });
WebAppContext bb2 = new WebAppContext();
bb2.setServer(server);
bb2.setContextPath("/");
bb2.setWar("src/main/webapp");
server.addHandler(bb);
server2.addHandler(bb2);
try {
server.start();
server2.start();
} catch (Exception e) {
e.printStackTrace();
System.exit(100);
}
}
}
If you use some other handler, replace that with the webapp handler.
That being said, I'm not sure that this is the right way of doing it.

Related

Remotely access an EJB across a network or networks from client

Assuming a CLI or Swing interface client, how is a remote Bean accessed through Glassfish? By obtaining a reference to the BeanManager?
sample code:
Hashtable contextArgs = new Hashtable();
// First you must specify the context factory.
// This is how you choose between jboss implementation
// vs. an implementation from Sun or other vendors.
contextArgs.put( Context.INITIAL_CONTEXT_FACTORY, "com.jndiprovider.TheirContextFactory" );
// The next argument is the URL specifying where the data store is:
contextArgs.put( Context.PROVIDER_URL, "jndiprovider-database" );
// (You may also have to provide security credentials)
// Next you create the initial context
Context myCurrentContext = new InitialContext(contextArgs);
http://en.wikipedia.org/wiki/Java_Naming_and_Directory_Interface#Basic_lookup
So, for a CLI app to access a running glassfish app server, it would use something along the lines of:
Context context = null;
try {
context = new InitialContext();
hello = (Hello) context.lookup("java:global/SalutationApp/SalutationApp-ejb/Hello");
hello.myRemoteMethod();
} catch (Exception e) {
e.printStackTrace();
}
only with a specified URL to connect to a specific glassfish instance? How is a connection established?
If you are doing a real remote lookup, you cannot do it through the CDI's BeanManager, since the Swing GUI is not local.
First you need to configure the application server to allow remote calls - this most likely includes some authentication settings, but I have never done this on Glassfish.
Here is how we lookup the remote interface of our EJB bean in one of our own Swing applications that accesses a EJB deployed on JBoss 4.
First, we added a jndi.properties into the ClassPath of the UI, which contains the information which server is responsible for the naming lookup (note that the port number is application server specific). This is a jndi.properties file used in one of our own Swing GUIs:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=server.local\:1199
Next, given that your naming context now knows how to lookup remote JNDI names, you can use something like this (again, this is used in our Swing UI):
InitialContext ctx = new InitialContext();
MyRemote mr = (MyRemote) ctx.lookup("global/jndi/name/of/remote/interface");
Instead of using the properties file, you can also configure the InitialContext by passing config values in code, something like this:
Properties env = new Properties();
env.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory"); // depends on your server
env.setProperty(Context.PROVIDER_URL, "jnp://server.local:1099/");
env.setProperty(Context.SECURITY_PRINCIPAL, "user");
env.setProperty(Context.SECURITY_CREDENTIALS, "password");
InitialContext ctx = new InitialContext(env);
This answer is not complete, but I hope this helps to get you started.

Publishing multiple Endpoints with built-in Java JAX-WS web server

So I have 2 implementations, Impl1 and Impl2, of a web service interface class. I would like to publish both under the same domain and port but with different URLS:
http://some.domain.asd/ws1 and http://some.domain.asd/ws2
Apparently, I should be able to create a configuration where I have 2 Endpoints, one for each implementation, bound to a single web server instance.
Note that I am not deploying but using the Java 7 internal publishing mechanism.
I noticed that instead of calling
Endpoint.publish(URL, new Implementor());
to directly publish a web service, I can call
Endpoint ep = Endpoint.create(new Implementor());
ep.publish(serverContext);
to publish the Implementor at a specific serverContext. What exactly is such a serverContext and how do I use it? I noticed that the publish method instantiates a javax.xml.ws.spi.Provider class and uses it for publishing purposes. But that is apparently not what I am looking for. Ideally, I would like a solution that resembles something like this:
Object serverContext = new Server(URL);
Endpoint impl1 = Endpoint.create(new Impl1());
Endpoint impl2 = Endpoint.create(new Impl2());
impl1.publish(serverContext);
impl2.publish(serverContext);
Can this even be done with the built-in publishing system, maybe using EndpointReferences objects? Or am I required to use a web service container to deploy my Endpoints seperately?
Publishing multiple Endpoints running on the same port could be achieved with this code :
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
Endpoint.publish("http://localhost:8888/ws/send", new SendServiceImpl());
Endpoint.publish("http://localhost:8888/ws/send23", new SendServiceImpl());
}
}
Running this locally in Eclipse it works , but when you deploy it to another server its broken.
To fix this you can either use http://0.0.0.0:8888 instead of localhost or the correct internal ip-address of the server.
You find it running:
windows: ipconfig
unix: ifconfig
It looks something like this: 192.168.100.55.
I stumbled across this problem today; I kept getting "java.net.BindException: Address already in use" when publishing two different endpoints to the same host+port. The solution is to instantiate the HttpServer yourself and "bind" each endpoint to this server:
package mypackage;
import com.sun.net.httpserver.HttpServer;
import javax.xml.ws.Endpoint;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
public static void main(String[] args) throws IOException {
final HttpServer httpServer = HttpServer.create(new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 8080), 16);
final Endpoint fooEndpoint = Endpoint.create(new FooImpl());
fooEndpoint.publish(httpServer.createContext("/Foo"));
final Endpoint barEndpoint = Endpoint.create(new BarImpl());
barEndpoint.publish(httpServer.createContext("/Bar"));
httpServer.start();
}

Access an service in jboss through JNDI (RMI?)

I need to make an service in jboss and access it through JNDI on the client side.
I have been playing around a bit with JNDI and made something like this on the client side:
import javax.naming.*;
public class App {
public static void main(String[] args) throws NamingException {
App app = new App();
app.setSysProp();
app.setObject();
app.getObject();
}
public void setSysProp() {
System.setProperty(Context.PROVIDER_URL, "127.0.0.1:1099");
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
}
public void setObject() throws NamingException {
Context context = new InitialContext();
MyObject obj = new MyObject();
obj.setName("NameOfMyObject");
context.bind("obj", obj);
}
public void getObject() throws NamingException {
Context context = new InitialContext();
MyObject obj = (MyObject) context.lookup("obj");
System.out.println(obj.getName());
}
}
This only binds and object to jndi on the client side and later retrieves it.
Now what i want is to bind a similar object on the server side (Jboss 4.2.3) and through it make some operations on the server. How can this be done? Ive read that something named RMI should be used in this case but what exactly is that and how to use it?
Ive read that something named RMI should be used in this case but what exactly is that and how to use it?
RMI is the Java standar API for Remote Method Invocation. It allows you execute a method on a object that reside in other Java Virtual Machine. Take in mind that you don't need a application server like JBoss to communicate with a remote java object. This link provides a simple tutorial.(notice that JBoss or any other app server is not mentioned)
I need to make an service in jboss and access it through JNDI on the client side.
This is a different thing. Although, JBoss (as a Java EE specification compliant server) use RMI extensively, you don't need understand how this API works. What you need is to create a server side component called EJB which allows you to have a service running on a server.
How can this be done?
There are hundred of tutorials about how to implement a basic EJB. Choose one compatible with your JBoss version due to some implementation details often change from one version to another.
You will also find that EJB specification has been evolving. With JBoss 4.2.3 and Java 5 you can start with EJB 3.0 which is easier than the previous one (2.1)

How does the JNDI lookup work in this JMS example?

I am having a hard time to understand the JNDI part of the following JMS example.
public static void main(String[] args) {
try {
// Gets the JNDI context
Context jndiContext = new InitialContext();
// Looks up the administered objects
ConnectionFactory connectionFactory = (ConnectionFactory)
jndiContext.lookup("jms/javaee7/ConnectionFactory");
Destination queue = (Destination) jndiContext.lookup("jms/javaee7/Queue");
// Sends a text message to the queue
try (JMSContext context = connectionFactory.createContext()) {
context.createProducer().send(queue, "Text message sent at " + new Date());
}
} catch (NamingException e) {
e.printStackTrace();
}
}
The book where I got this example didn't mention the setup to make this JNDI lookup possible. For example, in
ConnectionFactory connectionFactory = (ConnectionFactory)
jndiContext.lookup("jms/javaee7/ConnectionFactory");
should there be some kind of server running so that the jndiContext can get a hold of a ConnectionFactory object? In general, what sort of setup is required for the JNDI lookup above to work?
Thank you very much.
In general, JNDI is a service that provides a set of objects to be used by application. This service is usually provided by application server or web server or a dedicated LDAP server.
If the tutorial you are trying to follow explains the JMS tutorial in the context of web application, then most likely there are some setups to be done in the application server (e.g. Glassfish, JBoss) or web server (e.g. Tomcat).
The way to access JNDI also depends on the provider. Usually, this involves a configuration file (either properties file, or XML file).
Another alternative to use JMS is to utilize a dedicated JMS provider such as ActiveMQ. This way, you don't need any application server. Your application can just be a standalone java application (i.e. not necessarily a web application). Accessing objects provided by ActiveMQ via JNDI is explained here: https://activemq.apache.org/jndi-support.html.
General JNDI tutorial: http://docs.oracle.com/javase/tutorial/jndi/

Using EJBs with regular java classes. Trying to instantiate a stateless EJB

I have a large web project in Java EE 6 so far everything is working great.
Now I'm adding a new class that takes twitter information and returns a string. So far the strings have been extracted from the JSON file from twitter and are ready to be persisted in my database. My problem is I'm not sure how to pass information from the EJB that normally handles all of my database calls. I'm using JPA and have a DAO class that managers all database access. I already have a method there for updateDatabase(String). I'd like to be able to call updateDatabase(String) from the class that has the strings to add but I don't know if it's good form to instantiate a stateless bean like that. Normally you inject beans and then call just their class name to access their methods. I could also maybe try and reference the twitter string generating class from inside of the EJB but then I'd have to instantiate it there and mess with main() method calls for execution. I'm not really sure how to do this. Right now my Twitter consuming class is just a POJO with a main method. For some reason some of the library methods did not work outside of main in face IOUtils() API directly says "Instances should NOT be constructed in standard programming".
So on a higher level bottom line, I'm just asking how POJO's are normally "mixed" into a Java EE project where most of your classes are EJBs and servlets.
Edit: the above seems confusing to me after rereading so I'll try to simplify it. basically I have a class with a main method. I'd like to call my EJB class that handles database access and call it's updateDatabase(String) method and just pass in the string. How should I do this?
Edit: So it looks like a JNDI lookup and subsequence reference is the preferred way to do this rather than instantiating the EJB directly?
Edit: these classes are all in the same web project. In the same package. I could inject one or convert the POJO to an EJB. However the POJO does have a main method and some of the library files do not like to be instantiated so running it in main seems like the best option.
My main code:
public class Driver {
#EJB
static RSSbean rssbean;
public static void main(String[] args) throws Exception {
System.setProperty("http.proxyHost", "proxya..com");
System.setProperty("http.proxyPort", "8080");
/////////////auth code///////////////auth code/////////////////
String username = System.getProperty("proxy.authentication.username");
String password = System.getProperty("proxy.authentication.password");
if (username == null) {
Authenticator.setDefault(new ProxyAuthenticator("", ""));
}
///////////////end auth code/////////////////////////////////end
URL twitterSource = new URL("http://search.twitter.com/search.json?q=google");
ByteArrayOutputStream urlOutputStream = new ByteArrayOutputStream();
IOUtils.copy(twitterSource.openStream(), urlOutputStream);
String urlContents = urlOutputStream.toString();
JSONObject thisobject = new JSONObject(urlContents);
JSONArray names = thisobject.names();
JSONArray asArray = thisobject.toJSONArray(names);
JSONArray resultsArray = thisobject.getJSONArray("results");
JSONObject(urlContents.substring(urlContents.indexOf('s')));
JSONObject jsonObject = resultsArray.getJSONObject(0);
String twitterText = jsonObject.getString("text");
rssbean.updateDatabase("twitterText");
}
}
I'm also getting a java.lang.NullPointerException somewhere around rssbean.updateDatabase("twitterText");
You should use InitialContext#lookup method to obtain EJB reference from an application server.
For example:
#Stateless(name="myEJB")
public class MyEJB {
public void ejbMethod() {
// business logic
}
}
public class TestEJB {
public static void main() {
MyEJB ejbRef = (MyEJB) new InitialContext().lookup("java:comp/env/myEJB");
ejbRef.ejbMethod();
}
}
However, note that the ejb name used for lookup may be vendor-specific. Also, EJB 3.1 introduces the idea of portable JNDI names which should work for every application server.
Use the POJO as a stateless EJB, there's nothing wrong with that approach.
From the wikipedia: EJB is a server-side model that encapsulates the business logic of an application.
Your POJO class consumes a web service, so it performs a business logic for you.
EDIT > Upon reading your comment, are you trying to access an EJB from outside of the Java EE container? Because if not, then you can inject your EJB into another EJB (they HAVE to be Stateless, both of them)
If you have a stand alone program that wishes to access an EJB you have a couple of options.
One is to simply use JNDI to look up the EJB. The EJB must have a Remote interface, and you need to configure the JNDI part for you container, as well as include any specific container jars within your stand alone application.
Another technique is to use the Java EE artifact know as the "application client". Here, there is a container provider wrapper for your class, but it provides a run time environment very similar to running the class within the container, notably you get things like EJB injection.
You app still runs in a separate JVM, so you still need to reference Remote EJBs, but the app client container handles a bunch of the boiler plate in getting your app connected to the server. This, too, while a Java EE artifact, is also container dependent in how to configure and launch an app client application.
Finally, there is basically little difference in how a POJO interact with the EJB container this way in contrast to a POJO deployed within the container. The interface is still a matter of getting the EJB injected (more easily done in Java EE 6 than before) or looking up a reference via JNDI. The only significant difference being that a POJO deployed in the container can use a Local interface instead of the Remote.

Categories

Resources