Embedding Jetty 9.3 with modular XmlConfiguration - jetty

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)

Related

Inject Jar and replace classes in running JVM

I want to be able to replace and add some classes to an already running JVM. I read that I need to use CreateRemoteThread, but I don't completely get it. I read this post on how to do it (Software RnD), but I can't figure out what it does and why. Besides that, it only introduces new classes, but doesn't change existing ones. How can I do it with C++?
You don't even need CreateRemoteThread - there is an official way to connect to remote JVM and replace loaded classes by using Attach API.
You need a Java Agent that calls Instrumentation.redefineClasses.
public static void agentmain(String args, Instrumentation instr) throws Exception {
Class oldClass = Class.forName("org.pkg.MyClass");
Path newFile = Paths.get("/path/to/MyClass.class");
byte[] newData = Files.readAllBytes(newFile);
instr.redefineClasses(new ClassDefinition(oldClass, newData));
}
You'll have to add MANIFEST.MF with Agent-Class attribute and pack the agent into a jar file.
Then use Dynamic Attach to inject the agent jar into the running VM (with process ID = pid).
import com.sun.tools.attach.VirtualMachine;
...
VirtualMachine vm = VirtualMachine.attach(pid);
try {
vm.loadAgent(agentJarPath, options);
} finally {
vm.detach();
}
A bit more details in the article.
If you insist on using C/C++ instead of Java API, you may look at my jattach utility.

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.

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.

Gradle: How do I publish a zip from a non-java project and consume it in a java project?

I have a multi-project setup. I created a non-java project whose artifact is a zip file that I will unzip in another project. So the idea is as below
my-non-java-project
build.gradle
------------
apply plugin: 'base'
task doZip(type:Zip) { ... }
task build(dependsOn: doZip) << {
}
artifacts {
archives doZip
}
some-java-project
build.gradle
------------
apply plugin: 'war'
configurations {
includeContent // This is a custom configuration
}
dependency {
includeContent project(':my-non-java-project')
}
task expandContent(type:Copy) {
// Here is where I would like get hold of the all the files
// belonging to the 'includeContent' configuration
// But this is always turning out to be empty. Not sure how do I publish
// non-java content to the local repository (as understood by groovy)
}
So, my question is, how do I publish the artifacts of a non-java project to the internal repository of groovy such that I can pick it up at another java-based project?
Not exactly sure what you're after, but here's a quick-and-dirty way to get access to the FileCollection of the :my-non-java-project:doZip task outputs:
project(":my-non-java-project").tasks.getByName("doZip").outputs.files
Note that the archives configuration is added by the Java plugin, not the Base plugin. But you can still define a custom configuration in my-non-java-project and add the artifact to it with the code in your OP:
//in my-non-java-project/build.gradle
configurations {
archives
}
artifacts {
archives doZip
}
Then you can access the task outputs via the configuration, like so (again, quick-and-dirty):
//in some-java-project/build.gradle
project(":my-non-java-project").configurations.archives.artifacts.files
Note that you can expand the content of your zip file using zipTree.
If you need to actually publish the zip produced by my-non-java-project, you can read about that here.

Embed jetty in java app and export as jar

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}