I have a question about Protocol.FILE usage in this example from the Restlet site
// URI of the root directory.
public static final String ROOT_URI = "file:///c:/restlet/docs/api/";
[...]
// Create a component
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8182);
component.getClients().add(Protocol.FILE);
// Create an application
Application application = new Application() {
#Override
public Restlet createInboundRoot() {
return new Directory(getContext(), ROOT_URI);
}
};
// Attach the application to the component and start it
component.getDefaultHost().attach(application);
component.start();
Why it is needed to add Protocol.FILE to the list of client connectors in order to serve directory/file content?
Simply because you use this protocol within the ROOT_URI variable ;-) Regarding protocols, you need to explicitly add them when creating the Restlet component. Client connectors provide a way to use protocols to access resources (local or remote).
Here are some more details about what happens under the hood:
When adding a Restlet extension in the classpath, some elements are registered within the engine. You can have converters, server connectors, client connectors, ... You can see what is registered on the instance of the Engine itself:
List<ConnectorHelper<Client>> clientConnectors
= Engine.getInstance().getRegisteredClients();
for (ConnectorHelper<Client> clientConnector : clientConnectors) {
System.out.println(clientConnector);
}
Regarding client connectors, they correspond to entities that are able to handle particular protocol(s). For example, the Jetty extension providers a client connector to execute HTTP and HTTPS requests based on the Jetty client API.
To actually be able to use these registered client connectors, you need to enable them by specifying the protocol you want to use. For example, if you add the HTTP protocol, Restlet will find the first client connector in the list of registered one that is able to handle this protocol. For execute HTTP request, it will use this connector. If there is no available connector, it will throw an exception...
In your case, the client connector for the FILE protocol is provided by Restlet core itself so it's automatically registered. But you need to explicitly tell Restlet that you want to use this protocol.
Hope it helps you,
Thierry
Related
Problem:
I'm trying to get the dynamically selected HTTP port from OPS4J Pax Web within my application code at runtime.
Setup:
I have a custom Apache Karaf 4.4.0 distribution that installs the http Karaf Feature as a boot feature. The http Karaf Feature uses the OPS4J Pax Web implementation of the Http Service Specification with a Jetty web server. According to the Pax Web User Guide, the property org.osgi.service.http.port in the configuration file org.ops4j.pax.web.cfg has been set to 0 so that Pax Web automatically selects an HTTP port. This part works as expected.
Investigations:
I have tried the following approaches to read the HTTP port at runtime from different sources. Unfortunately, I wasn't successful with any of them.
Reading the property org.osgi.service.http.port from the configuration file org.ops4j.pax.web.cfg via the ConfigurationAdmin service resulted in the value 0.
Reading the HTTP port via an injected HttpService (#Reference HttpService ...) didn't work because the HttpService does not provide a method to get the HTTP port.
Reading the HTTP port via an injected WebContainer service from Pax Web (#Reference WebContainer ...) didn't work because the WebContainer service does not provide a method to get the HTTP port.
Current workaround:
As a current workaround, I set the property org.osgi.service.http.port in the configuration file org.ops4j.pax.web.cfg for the root Karaf Container to a fixed value. For all child Karaf Containers, the property is commented out and the HTTP port is selected by a small code snippet and passed as a JVM argument before the child Karaf Containers are started via the InstanceService. This allows me to read the HTTP port as a system property (System.getProperty(...)) in my application code.
However, I would like to make use of the possibility to let Pax Web automatically select an HTTP port, so maybe someone knows how the get the dynamically selected HTTP port at runtime.
Many thanks in advance.
Solution:
Thanks to Grzegorz Grzybek, I managed to get the dynamically selected HTTP port at runtime with the following code snippet:
#Reference
private HttpServiceRuntime httpServiceRuntime;
...
Map<String, Object> properties = httpServiceRuntime.getRuntimeDTO().serviceDTO.properties;
String[] localHttpEndpoints = (String[]) properties.get(HttpServiceRuntimeConstants.HTTP_SERVICE_ENDPOINT);
URL localHttpEndpointUrl = new URL(localHttpEndpoints[0]);
int httpPort = localHttpEndpointUrl.getPort();
In Pax Web 8 (available since Karaf 4.4.0) you can grab an instance of org.osgi.service.http.runtime.HttpServiceRuntime service and check its standard osgi.http.endpoint property. In my case it was:
objectClass = [org.osgi.service.http.runtime.HttpServiceRuntime]
osgi.http.endpoint = [http://0.0.0.0:44067/]
osgi.http.service.id = [107]
service.bundleid = 70
service.changecount = 0
service.id = 108
service.scope = singleton
while the PID property was 0:
karaf#root()> property-list --pid org.ops4j.pax.web
felix.fileinstall.filename = file:/data/servers/apache-karaf-4.4.1/etc/org.ops4j.pax.web.cfg
javax.servlet.context.tempdir = /data/servers/apache-karaf-4.4.1/data/pax-web/tmp
org.apache.karaf.features.configKey = org.ops4j.pax.web
org.osgi.service.http.enabled = true
org.osgi.service.http.port = 0
org.osgi.service.http.secure.enabled = false
My webapp is accessed via http and makes itself http-calls. For that I use jaxrs-client. Since Client is said to be an expensive resource, it is initialized once and reused within requests.
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target(baseUri).path(...);
During requests an http-call is made like this:
Builder request = webTarget.request(MediaType.APPLICATION_JSON);
Response response = request.post(...);
try {
// evaluate response
}
finally {
response.close();
}
So everything works fine, as long as the webapp is deployed on TomEE or no parallelism takes place.
But when the code gets executed concurrently within Wildfly, then it fails with
Caused by: java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.
at org.apache.http.util.Asserts.check(Asserts.java:34)
at org.apache.http.impl.conn.BasicClientConnectionManager.getConnection(BasicClientConnectionManager.java:162)
at org.apache.http.impl.conn.BasicClientConnectionManager$1.getConnection(BasicClientConnectionManager.java:144)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:423)
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:882)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
The error is generated by Wildfly, apparently using apache-httpclient as part of its JAXRS implementation provider.
Asking google, one gets hints recommending settings for REST-EASY or apache-httpclient (pool size or specific HttpClientConnectionManager).
But my application has no dependency to one of them. It merely depends on javax:javaee-api:7.0
My question: Is there a vendor-independent way to configure javax.ws.rs.client.Client being able to make calls concurrently?
The short answer to your question is..no. Here's the long answer:
Your code has a direct dependency on the jax-rs api (interfaces) defined in javaee-api. You deploy the code into wildfly, whose runtime provides Rest-Easy as a particular implementation of JAX-RS. Wildfly's dependency management/class loading takes care of loading Rest-Easy's concrete implementation of the jax-rs api.
Rest-Easy makes use of the apache http client (the apache-http client is not an implementation of the jax-rs api, Rest Easy is) as the underlying http client. Without configuration, the apache-http client will run with BasicClientConnManager as the default. To handle concurrent requests you'll need explicitly configure a multithreaded connection manager - see the apache http-client documentation http-client documentation for details - or let me know if you'd like an example.
I am looking for a way to configure during runtime (say, via a properties file, or deployment descriptor) which services in my Jersey-based application are available, i.e. so that services can be enabled or disabled by an administrator at the container level.
Our app presently exposes 15 different endpoints. It has 1 Application annotated with #ApplicationPath with 3 classes annotated with #Path, and within those 3 classes are 15 different methods annotated with the usual #Path/#/#Produces.
My app has a few different techniques for reading its runtime configuration, e.g. settings to connect to database resources, watching a properties file for changes, etc. What I want to do is add some configuration values so that administrators can enable/disable the 3 classes or any of the individual endpoints within those classes at the Jersey level. Could someone suggest the best way to do this?
Taking that a step further, we want to control this configuration in runtime, so if the configuration changes, we can update the jersey configuration to enable/disable the changed services without having to restart our container (which is Tomcat in this case).
Any advice appreciate! Thanks!
I don't know if this is possible natively with Jersey, but one thing I can think of is to just use a Jersey prematching filter to determine if the endpoints are disabled. You can use a service that can also act as a listener and update the disabled endpoints accordingly. If the endpoint is disabled, then just return a 404.
#Provider
#PreMatching
public class DisabledEndpointsFilter implements ContainerRequestFilter {
#Inject
private ConfigurationService configuration;
#Override
public void filter(ContainerRequestContext request) throws IOException {
final List<String> disabledEndpoints = this.configuration.getDisabledEndpoints();
final String path = stripLeadingSlash(request.getUriInfo().getPath());
for (String endpoint: disabledEndpoints) {
endpoint = stripLeadingSlash(endpoint);
if (path.startsWith(endpoint)) {
request.abortWith(Response.status(404).build());
return;
}
}
}
}
I was playing around with this and put together a working POC. You can checkout the Github Repo.
I would recommend use apache camel for this. With camel you can control the http requests combined with a embedded jetty server as proxy.
http://camel.apache.org/jetty.html
I have seen many examples on how to configure Jetty for HTTPS SSL for Jetty but they all seem to utilize a separate Server class containing a main method for execution. I want to execute my WebServlet as a standard servlet configured via the web.xml file. I currently have:
#WebServlet
public class MonitoringServlet extends WebSocketServlet {
#Override
public void configure(WebSocketServletFactory factory) {
factory.register(MonitoringSocket.class);
}
}
Where would I place my SSL Servlet configuration code? In the configure method of this Servlet? In the init method?
I do understand that in this case there is no need for instantiating a Server object and using .start() and .join
Servlets are just a means of producing a response to a request.
Typically a request can be from HTTP/0.9, HTTP/1.0, HTTP/1.1, or HTTP/2.
Using SSL/TLS for the secure part of the protocol.
Technically speaking, HTTP isn't even required for Servlets to function.
The protocol used to submit the request is outside of the control of the Servlet you are implementing to provide a response.
In Jetty, you'll want:
a Server instance
at least 1 Connector configured for SSL/TLS
at least 1 handler assigned to the Server
Using servlets without all of the baggage of a "web application" (a "web application" typically has a WEB-INF/web.xml, WEB-INF/classes, and WEB-INF/lib/*.jar) this would be a ServletContextHandler
Using servlets with a "web application" this would be a WebAppContext
This setup can come from a configured ${jetty.base} in the jetty-distribution or via embedded-jetty use of Java to build up the server, its connectors, and its handlers.
I need to call a web service with a java client.
This service authenticates clients through certificates at the message level (Ws-Security, not SSL).
It should be possible since, I can generate web services with JAX-WS with mutual certificate security in this dialog.
But I don't manage to create a client. Does anyone has an idea ?
I did not tried it myself, but from http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc/ :
Configuring Message Security Using XWSS
The Application Server contains all of the JAR files necessary to use XWS-Security for securing JAX-WS applications, however, in order to view the sample applications, you must download and install the standalone Java WSDP bundle. You can download the Java WSDP from http://java.sun.com/webservices/downloads/webservicespack.html.
To add message security to an existing JAX-WS application using XWSS, follow these steps on the client side:
Create a client security configuration. The client security configuration file specifies the order and type of message security operations that will be used for the client application. For example, a simple security configuration to perform a digital signature operation looks like this:
<xwss:Sign id="s" includeTimestamp="true">
<xwss:X509Token encodingType="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
valueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-
x509-token-profile-1.0#X509SubjectKeyIdentifier"
certificateAlias="xws-security-client"
keyReferenceType="Identifier"/>
</xwss:Sign>
</xwss:SecurityConfiguration>
</xwss:Service>
<xwss:SecurityEnvironmentHandler>
simple.client.SecurityEnvironmentHandler
</xwss:SecurityEnvironmentHandler>
For more information on writing and understanding security configurations and setting up SecurityEnvironmentHandlers, please see the Java Web Services Developer Pack 1.6 Tutorial at http://java.sun.com/webservices/docs/1.6/tutorial/doc/index.html.
In your client code, create an XWSSecurityConfiguration object initialized with the security configuration generated. Here is an example of the code that you would use in your client file. For an example of a complete file that uses this code, look at the example client in the \jaxws2.0\simple-doclit\src\simple\client\ directory.
FileInputStream f = new FileInputStream("./etc/client_security_config.xml");
XWSSecurityConfiguration config = SecurityConfigurationFactory.newXWSSecurityConfiguration(f);
Set security configuration information on the RequestContext by using the XWSSecurityConfiguration.MESSAGE_SECURITY_CONFIGURATION property. For an example of a complete file that uses this code, look at the example client in the \jaxws2.0\simple-doclit\src\simple\client\ directory.
// put the security config info
((BindingProvider)stub).getRequestContext().put(
XWSSecurityConfiguration.MESSAGE_SECURITY_CONFIGURATION,
config);
Invoke the method on the stub as you would if you were writing the client without regard to adding XWS-Security. The example for the application from the \jaxws2.0\simple-doclit\src\simple\client\ directory is as shown below:
Holder<String> hold = new Holder("Hello !");
stub.ping(ticket, hold);