I have a program that uses javax.xml.ws.Service to call a remote service defined by a WSDL. This program runs on the Google App Engine which, by default, sets the HTTP connection timeout to 5 seconds{1}. I need to increase this timeout value since this service often takes a long time to respond, but since this request is not being made with URLConnection, I cannot figure out how to call URLConnection.setReadTimeout(int){2}, or otherwise change the timeout.
Is there any way to globally set the HTTP connection timeout on the App Engine? And, for purposes of sharing knowledge, how would one go about solving this sort of problem generally?
{1}: https://developers.google.com/appengine/docs/java/urlfetch/overview#Requests
{2}: http://docs.oracle.com/javase/1.5.0/docs/api/java/net/URLConnection.html#setReadTimeout(int)
You could try setting the sun.net.client.defaultConnectTimeout and sun.net.client.defaultReadTimeout system properties documented here, e.g.
System.setProperty("sun.net.client.defaultReadTimeout", "30000");
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");
EDIT
Sorry, just re-read and noticed this is on Google App Engine. I don't know for sure, but given the litigious relationship Google and Oracle have lately, I'm guessing GAE doesn't run the Oracle JVM. I'll leave this here in case someone else runs into a similar problem.
Try this:
Port port = service.getPort(endPointInterface); //or another "getPort(...)"
((BindingProvider) port).getRequestContext()
.put(BindingProviderProperties.REQUEST_TIMEOUT, 30);
See https://developers.google.com/appengine/docs/java/urlfetch/usingjavanet
You can do something like this to get a URLConnection:
URL url = new URL("http://www.example.com/atom.xml");
URLConnection tempConnection = url.openConnection();
tempConnection.setReadTimeout(10);
For App Engine with JAX-WS you have to set the request context (tested today with SDK 1.9.15). For normal machines you cannot go higher than 60s and would have to switch to the bigger machines (Bx) for better use a task queue.
For local testing you would normally use BindingProviderProperties.CONNECT_TIMEOUT and BindingProviderProperties.REQUEST_TIMEOUT, but they are not on the App Engine JRE White List and your code inspection might constantly warn you about that.
The equivalent strings can be used though:
com.sun.xml.internal.ws.connect.timeout
com.sun.xml.internal.ws.connect.timeout
For deployment to App Engine:
com.sun.xml.ws.connect.timeout
com.sun.xml.ws.request.timeout
A full example how to apply that to auto-generated code from JAX-WS 2.x, values have to be provided in milliseconds:
#WebEndpoint(name = "Your.RandomServicePort")
public YourServiceInterface getYourRandomServicePort() {
YourRandomServiceInterface port = super.getPort(YOURRANDOMSERVICE_QNAME_PORT, YourRandomServiceInterface.class);
Map<String, Object> requestContext = ((BindingProvider)port).getRequestContext();
requestContext.put("com.sun.xml.ws.connect.timeout", 10000);
requestContext.put("com.sun.xml.ws.request.timeout", 10000);
return port;
}
Related
I have problem with vertx HttpClient.
Here's code which shows that tests GET using vertx and plain java.
Vertx vertx = Vertx.vertx();
HttpClientOptions options = new HttpClientOptions()
.setTrustAll(true)
.setSsl(false)
.setDefaultPort(80)
.setProtocolVersion(HttpVersion.HTTP_1_1)
.setLogActivity(true);
HttpClient client = vertx.createHttpClient(options);
client.getNow("google.com", "/", response -> {
System.out.println("Received response with status code " + response.statusCode());
});
System.out.println(getHTML("http://google.com"));
Where getHTML() is from here: How do I do a HTTP GET in Java?
This is my output:
<!doctype html><html... etc <- correct output from plain java
Feb 08, 2017 11:31:21 AM io.vertx.core.http.impl.HttpClientRequestImpl
SEVERE: java.net.UnknownHostException: failed to resolve 'google.com'. Exceeded max queries per resolve 3
But vertx can't connect. What's wrong here? I'm not using any proxy.
For reference: a solution, as described in this question and in tsegismont's comment here, is to set the flag vertx.disableDnsResolver to true:
-Dvertx.disableDnsResolver=true
in order to fall back to the JVM DNS resolver as explained here:
sometimes it can be desirable to use the JVM built-in resolver, the JVM system property -Dvertx.disableDnsResolver=true activates this behavior
I observed this DNS resolution issue with a redis client in a kubernetes environment.
I had this issue, what caused it for me was stale DNS servers being picked up by the Java runtime, i.e. servers registered for a network the machine was no longer connected to. The issue is first in the Sun JNDI implementation, it also exists in Netty which uses JNDI to bootstrap its list of name servers on most platforms, then finally shows up in VertX.
I think a good place to fix this would be in the Netty layer where the set of default DNS servers is bootstrapped. I have raised a ticket with the Netty project so we'll see if they agree with me! Here is the Netty ticket
In the mean time a fairly basic workaround is to filter the default DNS servers detected by Netty, based on whether they are reachable or not. Here is a code Sample in Kotlin to apply before constructing the main VertX instance.
// The default set of name servers provided by JNDI can contain stale entries
// This default set is picked up by Netty and in turn by VertX
// To work around this, we filter for only reachable name servers on startup
val nameServers = DefaultDnsServerAddressStreamProvider.defaultAddressList()
val reachableNameServers = nameServers.stream()
.filter {ns -> ns.address.isReachable(NS_REACHABLE_TIMEOUT)}
.map {ns -> ns.address.hostAddress}
.collect(Collectors.toList())
if (reachableNameServers.size == 0)
throw StartupException("There are no reachable name servers available")
val opts = VertxOptions()
opts.addressResolverOptions.servers = reachableNameServers
// The primary Vertx instance
val vertx = Vertx.vertx(opts)
A little more detail in case it is helpful. I have a company machine, which at some point was connected to the company network by a physical cable. Details of the company's internal name servers were set up by DHCP on the physical interface. Using the wireless interface at home, DNS for the wireless interface gets set to my home DNS while the config for the physical interface is not updated. This is fine since that device is not active, ipconfig /all does not show the internal company DNS servers. However, looking in the registry they are still there:
Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces
They get picked up by the JNDI mechanism, which feeds Netty and in turn VertX. Since they are not reachable from my home location, DNS resolution fails. I can imagine this home/office situation is not unique to me! I don't know whether something similar could occur with multiple virtual interfaces on containers or VMs, it could be worth looking at if you are having problems.
Here is the sample code which works for me.
public class TemplVerticle extends HttpVerticle {
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
// Create the web client and enable SSL/TLS with a trust store
WebClient client = WebClient.create(vertx,
new WebClientOptions()
.setSsl(true)
.setTrustAll(true)
.setDefaultPort(443)
.setKeepAlive(true)
.setDefaultHost("www.w3schools.com")
);
client.get("www.w3schools.com")
.as(BodyCodec.string())
.send(ar -> {
if (ar.succeeded()) {
HttpResponse<String> response = ar.result();
System.out.println("Got HTTP response body");
System.out.println(response.body().toString());
} else {
ar.cause().printStackTrace();
}
});
}
}
Try using web client instead of httpclient, here you have an example (with rx):
private val client: WebClient = WebClient.create(vertx, WebClientOptions()
.setSsl(true)
.setTrustAll(true)
.setDefaultPort(443)
.setKeepAlive(true)
)
open fun <T> get(uri: String, marshaller: Class<T>): Single<T> {
return client.getAbs(host + uri).rxSend()
.map { extractJson(it, uri, marshaller) }
}
Another option is to use getAbs.
In the API documentation for Java Spark (not Apache spark), you can specify a port of 0 to have it automatically select a port. Great!
However, I cannot figure out how to get that port after the server is started. I can see it in the logs:
15:41:12.459 [Thread-2] INFO spark.webserver.JettySparkServer - >> Listening on 0.0.0.0:63134
But I need to be able to get to it programmatically, so that my integration tests are able to run reliably every time.
So how do I get that port?
I could find no way to get this information in the API, and so I filed an issue on their github.
I was able to get at it via an ugly pile of reflection:
/**
* Meant to be called from a different thread, once the spark app is running
* This is probably only going to be used during the integration testing process, not ever in prod!
*
* #return the port it's running on
*/
public static int awaitRunningPort() throws Exception {
awaitInitialization();
//I have to get the port via reflection, which is fugly, but the API doesn't exist :(
//Since we'll only use this in testing, it's not going to kill us
Object instance = getInstance();
Class theClass = instance.getClass();
Field serverField = theClass.getDeclaredField("server");
serverField.setAccessible(true);
Object oneLevelDeepServer = serverField.get(instance);
Class jettyServerClass = oneLevelDeepServer.getClass();
Field jettyServerField = jettyServerClass.getDeclaredField("server");
jettyServerField.setAccessible(true);
//Have to pull in the jetty server stuff to do this mess
Server jettyServer = (Server)jettyServerField.get(oneLevelDeepServer);
int acquiredPort = ((ServerConnector)jettyServer.getConnectors()[0]).getLocalPort();
log.debug("Acquired port: {}", acquiredPort);
return acquiredPort;
}
This works well for me in our integration tests, but I'm not using https, and it does reach about two levels deep into the API via reflection grabbing protected fields. I could not find any other way to do it. Would be quite happy to be proven wrong.
This will work on Spark 2.6.0:
public static int start (String keystoreFile, String keystorePw)
{
secure(keystoreFile, keystorePw, null, null);
port(0);
staticFiles.location("/public");
get(Path.CLOCK, ClockController.time);
get(Path.CALENDAR, CalendarController.date);
// This is the important line. It must be *after* creating the routes and *before* the call to port()
awaitInitialization();
return port();
}
Without the call to awaitInitialization() port() would return 0.
I recently set up a website and pushed it to production using Digital Ocean. However, I noticed that for both SEO purposes and to make Facebook Share work appropriately, I should set up my server to redirect www. requests to non-www. I'm running Play! Java 2.3 with a PostgreSQL database and the default Netty server. Any advice would be greatly appreciated.
There are lots of ways of redirecting. I wouldn't say DNS-redirects are the correct and only way of doing it, it's one way. Google is just fine with you doing a 301 redirect with Play.
Here's one way of accomplishing it with Play! filters (scala):
object NonWwwFilter extends Filter {
def apply(f:RequestHeader => Future[Result])(rh: RequestHeader): Future[Result] =
if (rh.host.startsWith("www.")) {
Future.successful(Results.MovedPermanently("https://" + rh.host.substring(4) + rh.uri))
} else {
f(rh)
}
}
The right way to do it is to do in not on the framework/webserver side, but on the DNS-server side.
You can do it in DNS-management area of GoDaddy or any other domain name registrar.
So I have a java program running within an Amazon EC2 instance. Is there a way to programatically get its own tags? I have tried instantiating a new AmazonEC2Client to us the describeTags() function but it only gives me null. Any help would be appreciated thank you.
Edit: To make things clearer, the instances are going to be unmanned worker machines spun up to solely do some computations
This should help you get started...
String instanceId = EC2MetadataUtils.getInstanceId();
AmazonEC2 client = AmazonEC2ClientBuilder.standard()
.withCredentials(new DefaultAWSCredentialsProviderChain())
.build();
DescribeTagsRequest req = new DescribeTagsRequest()
.withFilters(new Filter("resource-id", Collections.singletonList(instanceId)));
DescribeTagsResult describeTagsResult = client.describeTags(req);
List<TagDescription> tags = describeTagsResult.getTags()
You should be able to get the current instance id by sending a request to: http://169.254.169.254/latest/meta-data/instance-id. This only works within ec2. With this you can access quite a bit of information about the instance. However, tags do not appear to be included.
You should be able to take the instance id along with the correct authentication to get the instance tags. If you are going to run this on an instance, you may want to provide an IAM user with limited access instead of a user which has access to everything in case the instance is compromised.
While using user-data may be the simplest solution, the OP was asking specifically about the tagging, and unfortunately amazon hasn't made this as easy as it could be. However, It can be done. You want to use a combination of 2 amazon services.
First you need to retrieve the Instance ID. This can be achieved by hitting the URL from within your instance:
http://169.254.169.254/latest/meta-data/instance-id
Once you have the resource ID, you'll want to use Amazon's EC2 API to access the tags. Since you said you're using Java, I would suggest the Using the AWS SDK amazon makes available. Within this SDK you'll find a method called describeTags (documentation). You can use a Resource ID as one of the filters to get the specific tags to your instance. Supported filters are
tag key
resource-id
resource-type
I suggest doing this retrieval at boot using something like cloud-init and caching the tags on your server for use later if necessary.
I am working on a desktop based application that is like drop box, I have a function downloadFile(long fileId) that download file for me from web, desktop side of the application is in java where web service is written in .Net
I have generated WS client using netbeans
The issue is: Some times it happens that downloadFile(long fileId) function get stuck,
What ever the reason behind it, I want if web service function does not give any response till a given time I snatch the control back from that function and generate a new call after some time. Is it possible using java?
EDIT I think that it could be done if can set the request time out of the web service but i don't have idea how to set time out in the client generated by netbeans
In the class FileUpload that is root class of web service(Generated by netBeans) there were some constructors of the class and function of the super class, one of them i was using to create SOAP object. That was looking like
#WebEndpoint(name = "FileUploadSoap")
public FileUploadSoap getFileUploadSoap() {
return super.getPort(new QName("http://svc.qleapahead.com/",
"FileUploadSoap"), FileUploadSoap.class);
}
in this function i made some modifications in order to set time out parameter and this became like
#WebEndpoint(name = "FileUploadSoap")
public FileUploadSoap getFileUploadSoap() {
FileUploadSoap fileUploadSoap = super.getPort(new QName(
"http://svc.qleapahead.com/", "FileUploadSoap"),
FileUploadSoap.class);
((BindingProvider) fileUploadSoap).getRequestContext().put(
"com.sun.xml.internal.ws.request.timeout", 1000 * 2 * 60);
return fileUploadSoap;
}
and problem solved...
in short this statement helped me a lot
((BindingProvider) fileUploadSoap).getRequestContext().put(
"com.sun.xml.internal.ws.request.timeout", 1000 * 2 * 60);
Depending on the framework you use for calling the webservice, there will be some way of setting a readTimeout causing the call to fail with some kind of exception.
Cheers,