Embed jetty in java app and export as jar - jetty

I'm making a java application which embeds a Jetty web server, which in turn serves content developed with Google Web Toolkit. It's all working fine when run in Eclipse, but when I export it as a jar file all I get is a Jetty error message saying "File not found".
The Jetty server is launched like this:
WebAppContext handler = new WebAppContext();
handler.setResourceBase("./war");
handler.setDescriptor("./war/WEB-INF/web.xml");
handler.setContextPath("/");
handler.setParentLoaderPriority(true);
server.setHandler(handler);
try {
server.start();
server.join();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I suspect that the problem is the relative paths used in handler.setResourceBase() and handler.setDescriptor(). I've googled and tested lots of solutions to this but so far to no avail. Particularly I've tried using something like getClass().getResource("./war").toExternalForm() but this just throws Null exceptions.
I also tried:
ProtectionDomain protectionDomain = Start.class.getProtectionDomain();
URL location = protectionDomain.getCodeSource().getLocation();
but that only results in a Jetty serving a directory listing of the java classes.
Is there any way to do this?

Copy all files of the compiled GWT application into one of your Java packages. For instance:
my.webapp.resources
html/MyPage.html
gwtmodule/gwtmodule.nocache.js
...
(html, gwtmodule will become Java packages as well).
Configure the embedded Jetty instance to serve these files.
final String webDir = this.getClass().
getClassLoader().getResource("my/webapp/resources").toExternalForm();
final Context root = new Context(server, "/", Context.SESSIONS);
root.setContextPath("/");
root.setResourceBase(webDir);
root.addServlet(MyGwtService.class, "/servlets/v01/gwtservice");
This approach works for me both when the application is run from eclipse as well as when it is deployed.

I've posted a detailed description on how to do this here:
http://h30499.www3.hp.com/t5/HP-Software-Developers-Blog/Embedding-Jetty-in-a-Java-Main-Application/ba-p/6107503

It looks like ClassLoader.getResource does not understand an empty string or . or / as an argument. In my jar file I had to move all stuf to WEB-INF. So the code looks like
`contextHandler.setResourceBase(EmbeddedJetty.class.getClassLoader().getResource("WEB-INF").toExternalForm());`
so the context looks like this then:
ContextHandler:744 - Started o.e.j.w.WebAppContext#48b3806{/,jar:file:/Users/xxx/projects/dropbox/ui/target/ui-1.0-SNAPSHOT.jar!/WEB-INF,AVAILABLE}

Related

Using a HTTP Module on a Virtual Directory in IIS

I have a default website in my IIS where I have created one virtual directory "wsdls".
I would want to gather statistics on how many requests are triggered to my virtual directory. This would need a request interception at web server level and gather statistics. "HTTPModule" was one of the many solutions I have considered which is suitable for such scenario. Hence I have started building one.
For testing purpose, I wanted to create a HTTP Module and apply it on a particular extension files (say *.wsdl) and on every GET request of any .wsdl files in this virtual directory, I will want to redirect the application to "www.google.com". This would demonstrate a good example of how HTTP Module can be used and deployed on IIS.
HTTPModule which is written using Visual Studio is shown below,
namespace Handler.App_Code
{
public class HelloWorldModule : IHttpModule
{
public HelloWorldModule(){
}
public String ModuleName{
get { return "HelloWorldModule"; }
}
// In the Init function, register for HttpApplication
// events by adding your handlers.
public void Init(HttpApplication application){
application.BeginRequest +=
(new EventHandler(this.Application_BeginRequest));
application.EndRequest +=
(new EventHandler(this.Application_EndRequest));
}
private void Application_BeginRequest(Object source,
EventArgs e)
{
// Create HttpApplication and HttpContext objects to access
// request and response properties.
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
context.Response.Redirect("www.google.com");
}
private void Application_EndRequest(Object source, EventArgs e)
{
//Nothing to be done here
}
public void Dispose() { }
}
}
Now I have done a build of this project for x64 version and I am able to browser successfully the "dll" file. Now I have to register this dll in IIS and whenever I try to access the *.wsdl files, the requests automatically divert to "www.google.com". Here is the next step I have done,
Then I have enabled the Handler mappings as shown below,
I am assuming that is it!! Nothing more to be done. I should be able to intercept the requests for all HTTP requests which are of the form "*.wsdl". This means whenever I access any wsdl from the server, control should be going back to google(Because of the logic written in begin request ). But unfortunately, I failed in achieving it. What can be done here?
One thing I noticed is that when you are trying to redirect to an external URL use
http://
So change
context.Response.Redirect("www.google.com");
to
context.Response.Redirect("http://www.google.com", true);
I could solve the problem what I am facing and below are the observations which were missing in my understanding and which helped me in solving my problem:
Locating proper web.config file :
Every website in IIS will be having a web.config file to have control over the application.
Since I am working with "Default Website", this refers to the directory "C:\\inetpub\\wwwroot"
There will be a "web.config" file which would be present in this director. Please create it if not already present.
Modifying web.config :
Once you have identified the file which needs to be modified, just add necessary module configuration to web.config
In this case, we would want to add a Module to the default website, the probably setting would be shown below,
Adding contents to bin directory :
Now if you try to run the application, the IIS would not find any dll or executable to run and hence we would need to keep the executables at a particular location.
Create a director if not already present with the name "bin" at the root of the directory and place all the dlls which you would want this website to execute. Sample shown below,
General Points to be considered:
Proper access must be given for the folder which consists of dll.
It is ideally not suggested to modify the entire website. It would be ideal if one works only on their web application.
If web.config is not found, we can create one.
If bin is not present in the web root directory, we can create one.

Embedding Jetty 9.3 with modular XmlConfiguration

I am migrating from Jetty 8.1.17 to Jetty 9.3.9. Our application embeds Jetty. Previously we had a single XML configuration file jetty.xml which contained everything we needed.
I felt that with Jetty 9.3.9 it would be much nicer to use the modular approach that they suggest, so far I have jetty.xml, jetty-http.xml, jetty-https.xml and jetty-ssl.xml in my $JETTY_HOME/etc; these are pretty much copies of those from the 9.3.9 distribution. This seems to work well when I use start.jar but not through my own code which embeds Jetty.
Ideally I would like to be able to scan for any jetty xml files in the $JETTY_HOME/etc folder and load the configuration. However for embedded mode I have not found a way to do that without explicitly defining the order that those files should be loaded in, due to <ref id="x"/> dependencies between them etc.
My initial attempt is based on How can I programmatically start a jetty server with multiple configuration files? and looks like:
final List<Object> configuredObjects = new ArrayList();
XmlConfiguration last = null;
for(final Path confFile : configFiles) {
logger.info("[loading jetty configuration : {}]", confFile.toString());
try(final InputStream is = Files.newInputStream(confFile)) {
final XmlConfiguration configuration = new XmlConfiguration(is);
if (last != null) {
configuration.getIdMap().putAll(last.getIdMap());
}
configuredObjects.add(configuration.configure());
last = configuration;
}
}
Server server = null;
// For all objects created by XmlConfigurations, start them if they are lifecycles.
for (final Object configuredObject : configuredObjects) {
if(configuredObject instanceof Server) {
server = (Server)configuredObject;
}
if (configuredObject instanceof LifeCycle) {
final LifeCycle lc = (LifeCycle)configuredObject;
if (!lc.isRunning()) {
lc.start();
}
}
}
However, I get Exceptions at startup if jetty-https.xml is loaded before jetty-ssl.xml or if I place a reference in jetty.xml to an object from a sub-configuration jetty-blah.xml which has not been loaded first.
It seems to me like Jetty manages to do this okay itself when you call java -jar start.jar, so what am I missing to get Jetty to not care about what order the config files are parsed in?
Order is extremely important when loading the Jetty XML files.
That's the heart of what the entire start.jar and its module system is about, have an appropriate set of properties, the server classpath is sane, and ensuring proper load order of the XML.
Note: its not possible to have everything in ${jetty.home}/etc loaded at the same time, as you will get conflicts on alternate implementations of common technologies (something start.jar also manages for you)

Use wsse security header in soap message (Visual Studio 2015, .Net Framework 4.5)

I would like to consume a Soap Service provided by DHL. You can find the wsdl here: https://wsbexpress.dhl.com/sndpt/expressRateBook?WSDL
Therefore I created a new ClassLibrary in Visual Studio 2015 targeting .net framework 4.5.
Then I added a Web Reference to the created project by providing the wsdl address. I generated a proxy file with all types and ports in it but my first problem is, that the generated Service extends from System.Web.Services.Protocols.SoapHttpClientProtocol. As I read in recent posts it is not possible to get the wsse header to that proxy. Some posts advise to add wse but it seems wse is not supported by newer Visual Studio versions.
I tried to generate my proxy by svcutil. After that I added the generated .cs file to the project and copied the content of the generated config file to app.config. (of cause I removed the web reference)
Now the Service class extends System.ServiceModel.ClientBase. (I thought the generator in VS uses svctool internally. If microsoft want people to use wcf why does the generator generate non-wcf proxy files.
I also created a nunit testproject which should test my service, but If I use the version with the svcutil generated version I get an error. I try to translate it to english as the error is displayed in german:
Could not find a default endpoint element which points to the service contract. As I figured out this is because the proxy is in its own class library and therefor doesn't really have an app.config. But my test project is a class library too.
What would be the actual way to consume a web service which needs ws security Username/Password auth these days?
You can add the Web Reference in compatibility mode (I am guessing you are doing so). If you are not adding the reference in compatibility mode, do the following:
Right click on references Add Service Reference-> Advanced -> Add Web Reference (Below the compatibility section), type the URL of the WS and add the reference.
The WSE2.0 extensions are available as a Nuget Package at:
https://www.nuget.org/packages/Microsoft.Web.Services2/
Install the nuget package on the package manager console running the following nugget command:
Install-Package Microsoft.Web.Services2
After you installed the nuget package, you need to make sure your project is referencing the following DLL's:
System.Web
System.Web.Services
Microsoft.Web.Services2 (This will be added after you install the nuget package)
In order to use the WSE2.0 extensions, you need to actually modify the Proxy class that was created when you added the WebReference to inherit from "Microsoft.Web.Services2.WebServicesClientProtocol" instead of "System.Web.Services.Protocols.SoapHttpClientProtocol". Be aware that if you update the WebReference, the Proxy class will inherit againfrom SoapHttpClientProtocol.
Add the following using clauses to the code consuming the Proxy class:
using Microsoft.Web.Services2;
using Microsoft.Web.Services2.Security;
using Microsoft.Web.Services2.Security.Tokens;
After you make this changes, you code should look something like this:
var token = new UsernameToken("theUser", "thePassword", PasswordOption.SendHashed);
var serviceProxy = new ExpressRateBook.gblExpressRateBook();
SoapContext requestContext = serviceProxy.RequestSoapContext;
requestContext.Security.Timestamp.TtlInSeconds = 60;
requestContext.Security.Tokens.Add(token);
//The rest of the logic goes here...
I added the screenshot down below for your reference:
NOTE: I was unable to test the code since I am unfamiliar with the actual methods that you need to consume, the code displayed is just an example of what I saw in the proxy class, update it according to your needs. It should work fine if you follow the steps described before. Check the following link for more detailed instructions:
https://msdn.microsoft.com/en-us/library/ms819938.aspx
You can configure you Service Reference to add the Security Header as AW Rowse describes at http://cxdeveloper.com/article/implementing-ws-security-digest-password-nonce-net-40-wcf:
private void Configure()
{
System.Net.ServicePointManager.ServerCertificateValidationCallback = (senderX, certificate, chain, sslPolicyErrors) => { return true; };
defaultBinding = new BasicHttpBinding
{
Security =
{
Mode = BasicHttpSecurityMode.Transport,
Transport =
{
ClientCredentialType = HttpClientCredentialType.Digest
}
}
};
defaultToken = new UsernameToken(UserName, Password, PasswordOption.SendHashed);
defaultSecurityHeader = MessageHeader.CreateHeader(
"Security",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
defaultToken.GetXml(new XmlDocument())
);
}
And create you client/proxy like this:
public consulta_informacao_respttClient CriaConsultaClinicaClient()
{
var client = new consulta_informacao_respttClient(defaultBinding, new EndpointAddress("https://resqa.homologacao.unimed.coop.br/chs-integration-external-services-ptu-clinical/proxy-services/execute-query/execute-query-proxy-service"));
client.ClientCredentials.UserName.UserName = UserName;
client.ClientCredentials.UserName.Password = Password;
var scope = new OperationContextScope(client.InnerChannel);
OperationContext.Current.OutgoingMessageHeaders.Add(defaultSecurityHeader);
return client;
}
The properties you will need to create in your class are:
private BasicHttpBinding defaultBinding;
private UsernameToken defaultToken;
private MessageHeader defaultSecurityHeader;
You won't need to configure anything in app/web.config.

Autologin during development with Jetty

I have the usual setup: A webapp with a login screen and a small Java class which sets up Jetty to launch the app.
During development, we all waste a couple of seconds to log in after every change to the code which forces a restart. (No, JRebel doesn't help since it doesn't run the constructors again so it can miss some changes).
So I was wondering if I could patch the Jetty setup in such a way:
If I request /index.jsp, instead of going to the real JSP, it should load a servlet which fills in the username and password of the typical development user, logs him in, and then redirects to the main JSP of the app.
To make everything safe, I'll put this auto-login code into the test path, so it can't be deployed accidentally.
Now the question: How do I configure URL redirection/rewriting in Jetty from Java code? For obvious reasons, I don't want to touch web.xml.
Following the examples in , I came up with this code:
private WebAppContext webapp;
private void configureAutoLogin() {
ServletHolder holder = webapp.getServletHandler().newServletHolder();
holder.setName("autologin");
holder.setClassName( AutoLoginServlet.class.getName() );
webapp.getServletHandler().addServlet(holder);
ServletMapping mapping = new ServletMapping();
mapping.setServletName(holder.getName());
String[] paths = { "/autologin" };
mapping.setPathSpecs( paths );
webapp.getServletHandler().addServletMapping(mapping);
}
To make it more simple for users, I also created a directory jetty/ which contains a test.html where developers can add links to such URLs. To make sure this test HTML page can't be deployed accidentally, I add the jetty/ directory to the base resource of the WebAppContext:
File webAppDir = new File( "src/main/webapp" );
Resource webAppResource = new FileResource( webAppDir.toURI().toURL() );
Resource jettyDir = new FileResource( new File( "jetty" ).toURI().toURL() );
ResourceCollection resources = new ResourceCollection( webAppResource, jettyDir );
webapp.setBaseResource( resources );

Getting started with embedded Jetty

I just got started with embedded jetty. I'm stuck at some error messages. It's simple and straightforward few lines code, which I found online and wanted to test out.
import org.jaxen.Context;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.ServletHolder;
public class Main {
public static void main(String[] args) throws Exception {
ServletHolder sh = new ServletHolder(ServletContainer.class);
sh.setInitParameter("com.sun.jersey.config.property.resourceConfigClass", "com.sun.jersey.api.core.PackagesResourceConfig");
sh.setInitParameter("com.sun.jersey.config.property.packages", "jerseyplusjetty");
Server server = new Server(80);
ServletContextHandler sch = new ServletContextHandler(server, "/");
sch.addServlet(sh, "/*");
server.start();
server.join();
}
}
I have all jetty jars in java build path. But I kept getting errors: The constructor ServletHolder(Class) is undefined, The constructor Server(int) is undefined, ServletContextHandler cannot be resolved to a type.
If I remove the parameter inside ServletHolder and Server, it stops complaining. e.g. if I have: ServletHolder sh = new ServletHolder(); Server server = new Server();
But that's not right. I read Jetty docs and ServletHolder class can take parameters. Am I missing something here?
Just FYI on embedded Jetty in general... I have created a github project that I humbly submit may cover most of the embedded jetty issues that keep cropping up.
I've got examples for AbstractHandlers, Servlets, Jersey Servlets, static files, webapps and what not. Still working on RoR and Sinatra, but will get there.
See https://github.com/ZenGirl/EmbeddedJettyRepository for details.
Anyone want to contribute, just ask.
The version of ServletHolder I have takes a String or a servlet in the constructor. So instead of doing
new ServletHolder(ServletContainer.class) you should do new ServletHolder(ServletContainer.class.getCanonicalName()) or new ServletHolder(new ServletContainer()).
ServletContainer is a strange name for a servlet, make sure it is actually a servlet.
Also, be aware that there are number of different versions of Jetty (you're using an old one because in the new one all the classes are in org.eclipse.jetty package), and it's easy to pick up example code that refers to a different version to the one you've got. I would get jetty 7.2.2 from maven and use the example code here.