How to identify the URL of an Java web application from within? - java

My Java web application contains a startup servlet. Its init() method is invoked, when the web application server (Tomcat) is started. Within this method I need the URL of my web application. Since there is no HttpServletRequest, how to get this information?

You can't. Because there is no "URL of an Java web application" as seen "from within". A servlet is not tied to an URL, that is done from the outside. (Perhaps you have a Apache server that connects to a Tomcat - Tomcat can't know about it)
It makes sense to ask a HttpServletRequest for its url, because we are speaking of the information of a event (the URL that was actually used to generate this request), it does not make sense to ask for a configuration URL.

A workaround could be to perform the initialization lazy when the first request arrives. You can implement a filter that do that once, e.g. by storing a boolean flag in a static variable and synchronizing access to the flag correctly. But it implies a little overhead because each subsequent request will go through the filter which then bypass the initialization. It was just a thought.

There is nothing in the servlet API that provides this information, plus any given resource may be bound to multiple URL's.
What you CAN do, is to inspect the servlet context when you receive an actual request and see what URL was used.

Here is how it works for me and probably for most configurations:
public static String getWebappUrl(ServletConfig servletConfig, boolean ssl) {
String protocol = ssl ? "https" : "http";
String host = getHostName();
String context = servletConfig.getServletContext().getServletContextName();
return protocol + "://" + host + "/" + context;
}
public static String getHostName() {
String[] hostnames = getHostNames();
if (hostnames.length == 0) return "localhost";
if (hostnames.length == 1) return hostnames[0];
for (int i = 0; i < hostnames.length; i++) {
if (!"localhost".equals(hostnames[i])) return hostnames[i];
}
return hostnames[0];
}
public static String[] getHostNames() {
String localhostName;
try {
localhostName = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException ex) {
return new String[] {"localhost"};
}
InetAddress ia[];
try {
ia = InetAddress.getAllByName(localhostName);
} catch (UnknownHostException ex) {
return new String[] {localhostName};
}
String[] sa = new String[ia.length];
for (int i = 0; i < ia.length; i++) {
sa[i] = ia[i].getHostName();
}
return sa;
}

Related

How to really clean the property from System class?

I am trying to do a request on a REST service on two different web servers. On both servers it is necessary to present a keyStore, obviously they are different keyStores. Running the code below I am having successful only in the first request (for the test environment), but when I do the second request (for the staging environment), the request presents the first keyStore, in this case testKeyStore.jks.
I tried to clear the keyStore property of the System class and set a new value. In println it is displayed as if the property was changed, but when I see the log on the staging server, the testKeyStore was presented, not the stagingKeyStore.
If I change de order, first STAGING and then TEST, in doStaff() method, the second request fail because the stagingKeyStore is present in the test-server.
Is there some solution to solve this problem?
public void doStaff() {
callServer("TEST");
callServer("STAGING");
}
private void callServer(String enviroment) {
String url = "";
if ("TEST".equalsIgnoreCase(enviroment))
url = "https://test-server/dostaff";
else if("STAGING".equalsIgnoreCase(enviroment))
url = "https://staging-server/dostaff";
try {
System.clearProperty("javax.net.ssl.keyStore");
System.out.println(enviroment + " -> " + System.getProperty("javax.net.ssl.keyStore"));
if ("TEST".equalsIgnoreCase(enviroment)) {
System.setProperty("javax.net.ssl.keyStore", "C:\\temp\\testKeyStore.jks");
} else if("STAGING".equalsIgnoreCase(enviroment)) {
System.setProperty("javax.net.ssl.keyStore", "C:\\temp\\stagingKeyStore.jks");
}
System.out.println(enviroment + " -> " + System.getProperty("javax.net.ssl.keyStore"));
//...
} catch (Exception e) {
e.printStackTrace();
}
}

Request.BinaryRead with Java HttpURLConnection.getHeaderFieldKey

I have an ASP application that uploads a PDF file through Request.BinaryRead(Request.TotalBytes). The requests that I make, are made through a java application. The problem is that I have method in Java that iterates through the Header Field Keys of the object HttpURLConnection. When the iteration is made I get in my ASP code an error "cannot call binaryread after using request.form".
Here is my java code:
public String getCookieValue(HttpURLConnection con, String cookieKey) {
String cookieValue = null;
String headerName = null;
for (int i = 1; (headerName = con.getHeaderFieldKey(i)) != null; i++) {
if (headerName.equals("Set-Cookie")) {
String cookie = con.getHeaderField(i);
cookie = cookie.substring(0, cookie.indexOf(";"));
String cookieName = cookie.substring(0, cookie.indexOf("="));
if (cookieName.equals(cookieKey)) {
cookieValue = cookie.substring(cookie.indexOf("=") + 1, cookie.length());
}
}
}
return cookieValue;
}
The exact line of java code that breaks my ASP application is con.getHeaderFieldKey(i). When I upload the file without this Java application, the file is uploaded properly.
What can I do to bypass this issue ?
Thank you
Actually the problem here was that we are using a wrapper for the Session object. When we are trying to retrieve the information regarding the session Id we are using the Request.From method, and this intervenes with the Request.BinaryRead method which generates an error.

How to learn system (Windows) non-proxy hosts in Java

I'm writting a Java (1.7) application to be running on Windows. The application is accessing additional services running on the same host and other ones running in the Internet. The application can be run in two environments where in one, proxy settings must be specified (there is proxy when accessing the Internet); while in the other environment, the proxy settings must not be specified (there is no proxy).
I want the application to be simple and don't want its users bother with specification of the proxy settings on cmd-line (-Dhttp.proxyHost, etc.) - the application should learn the proxy settings from Windows system settings (IE / Tools / Internet Properties / Connections / LAN Settings).
I have written a piece of code that is supposed to learn that settings, see below. The trouble is that this piece of code does not identify localhost, 127.0.0.1 and my-computer-name (where my-computer-name is the name of my computer) as URLs where proxy should be by-passed when being accessed (yes, I do have 'Bypass proxy server for local addresses' checked). As a result, the application tries to access local services through the proxy which is wrong.
So far I've found out that one way to teach JVM not to use proxy for 'local addresses' is to list the strings (localhost, 127.0.0.1, my-computer-name) in Proxy Settings / Exceptions (Do not use proxy server for addresses beginning with). Obviously, this is not a good solution as usually no one is listing these strings there (the first check-box is enough for non-Java applications).
Second (trivial) solution would be just to count with these strings in my piece of code and do not use proxy settings for them even when JVM thinks otherwise. I don't think this is a good solution and if this is the only solution, IMHO, there is a defect in JVM.
I've found many resources in the Internet how to learn System proxy settings. But how to learn the non-proxy settings?
Thanks,
PP
public static final String HTTP_PROXY_HOST_KEY = "http.proxyHost";
public static final String HTTPS_PROXY_HOST_KEY = "https.proxyHost";
public static final String HTTP_PROXY_PORT_KEY = "http.proxyPort";
public static final String HTTPS_PROXY_PORT_KEY = "https.proxyPort";
public static final String NO_PROXY_HOSTS_KEY = "http.nonProxyHosts";
// provide list of urls which are to be accessed by this application and return proxy and non-proxy settings
private Properties getSystemProxyConfiguration(String[] urls) {
log.debug("Getting system proxy");
Properties properties = new Properties();
SortedSet<String> nonProxyHosts = new TreeSet<>();
for (String url : urls) {
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
throw new IllegalStateException(e);
}
InetSocketAddress address = getSystemProxy(uri);
if (address != null) {
if (url.toLowerCase().startsWith("https")) {
properties.put(HTTPS_PROXY_HOST_KEY, address.getHostString());
properties.put(HTTPS_PROXY_PORT_KEY, ""+address.getPort());
//todo verify that all previous URLs in this array are using the same proxy
log.debug("HTTPS proxy: " + address.getHostString() + ":" + address.getPort());
} else {
properties.put(HTTP_PROXY_HOST_KEY, address.getHostString());
properties.put(HTTP_PROXY_PORT_KEY, ""+address.getPort());
//todo verify that all previous URLs in this array are using the same proxy
log.debug("HTTP proxy: " + address.getHostString() + ":" + address.getPort());
}
} else { //todo DEFECT -> this does not find the non-proxy hosts (even though specified in IE Internet settings)
nonProxyHosts.add(uri.getHost());
}
}
if (nonProxyHosts.size() > 0) {
String nonProxyHostsString = nonProxyHosts.first();
nonProxyHosts.remove(nonProxyHostsString);
for (String nonProxyHost : nonProxyHosts) {
nonProxyHostsString = nonProxyHostsString + "|" + nonProxyHost;
}
properties.put(NO_PROXY_HOSTS_KEY, nonProxyHostsString);
log.debug("Non HTTP(S) proxy hosts: "+nonProxyHostsString);
} else {
log.debug("No non HTTP(S) proxy hosts set");
}
return properties;
}
private InetSocketAddress getSystemProxy(URI uri) {
List<Proxy> proxyList;
proxyList = ProxySelector.getDefault().select(uri);
if (proxyList != null && proxyList.size() > 0) { //todo DEFECT - this never returns DIRECT proxy for localhost, 127.0.0.1, my-computer-name strings
Proxy proxy = proxyList.get(0);
if (proxyList.size() > 1) {
log.warn("There is more " + proxy.type() + " proxies available. Use "+PROXY_PROPERTIES_FILE_NAME+" to set the right one.");
}
InetSocketAddress address = (InetSocketAddress) proxy.address();
return address;
}
return null;
}

How can I create a node recursively using zookeeper client library on Java?

I know this question has been already asked and answered for a zookeeper using python. The answer was good, however, I want something more related with the code. I've already implemented a method to create a node, but I want to do it recursively. The structure for my nodes will be like this:
ZOOKEEPER
WEB SERVER
SERVER1
SERVER2
MODULE CONNECTED
DATABASE MODULE
COMPUTER1
COMPUTER2
SERVICE MODULE
COMPUTER3
SEARCH MODULE
COMPUTER4
I have something like:
Zookeeper zk = new Zookeeper(...);
public void createNodeRecursively(String type) {
final String node = "/" + type + "/" + info.getIP() + ":" + info.getPort(); // Correct line
if (zk.exists("/" + type, null) == null) {
Object ctx = new Object();
StringCallback cb = new StringCallback() {
public void processResult(int rc, String path,
Object ctx, String name) {
if (name.equals("/" + type))// just in case
try {
zk.create(node, info.getBytes(),
Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);
} catch (Exception e) {
e.printStackTrace();
}
}
};
zk.create("/" + type, info.getBytes(), Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT, cb, ctx);
} else
zk.create(node, info.getBytes(), Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL);
}
}
As you can see I am using zk.create many times, so I want to make the method recursive in order to gain performance and have a better code, but I don't know how to start, I'll be very grateful if somebody can help me with this. Thank you very much in advance.
Zookeeper has useful properties:
Total order of (write) requests
Its asynchronous nature.
You can put on use that.
Simply issue whole tree as a bunch of asynchronous requests in correct order and then wait, until all of them successfully execute. Of course, you can ignore 'NodeExists' exceptions (but it is not good, due of the fact, that such errors will be written to logs).
I managed to achieve a better performance:
public void createNode(NodePath nodePath, NodeData nodeData, NodeRights nodeRights, NodeCreationHandler nodeCreationHandler) throws KeeperException, InterruptedException, ZookeeperCreationException {
if (zk == null) {
throw new ZookeeperCreationException("The zookeeper client has not been instanced.");
}
String targetPath = nodePath.getFullNodePath();
targetPath = targetPath.substring(1, targetPath.length());
byte[] serializedData = nodeData.serialize(new Object());
String[] array = targetPath.split(ICoordinationConstants.BASE_ROOT_SPTR);
String acum="";
for (int i = 0; i < array.length-1; i++) {
acum+=(ICoordinationConstants.BASE_ROOT_SPTR+array[i]);
if (zk.exists(acum, null) == null) {
zk.create(acum, serializedData, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
}
zk.create(acum+ICoordinationConstants.BASE_ROOT_SPTR+array[array.length-1], serializedData, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
}

Implementing a 'Send Feedback' feature in a Java desktop application

I would like to implement a 'Send Feedback' option in a Java desktop application. One which will pop up a box for the user to enter a comment, then send it to us along with a screenshot of the application window.
How would be the best way to communicate the data to us? Two obvious solutions spring to mind:
Email - I'm thinking that the application would connect to an SMTP server set-up by us, with the username/password somehow hidden in the code. SMTP over SSL for security (not of the data being sent, but of the SMTP username/password).
Web service - pretty self explanatory.
Which of these would be best, or is there a better alternative?
A webserivce would be far better, since the connection to an SMTP server might be blocked.
Another idea would be to use Google Docs. This would be like the website idea but you wouldnt need to set any server-side stuff yourself. You could create a Google Docs spreadsheet with the fields you will be collecting, then have your Java app write the submission to the spreadhseet using the google docs API. Then add a notification to the spreadsheet to automatically send you an email when a new row is written.
A web service sounds more reliable and less clumsy.
Client generally may make HTTP connections without firewall issues.
Much easier to setup, maintain and process HTTP server and requests.
As others mention, firewalls are an issue with SMTP. Still, there is a simple way to deliver mails without hosting your own infrastructure or "hidden" passwords. You could simply register a free mail account, e.g. gmail, and send mails directly to this address. As you aren't using Gmail's SMTP server as a relay, there is no need for username and password.
public static String[] lookupMailHosts(final String domainName) throws NamingException {
final InitialDirContext iDirC = new InitialDirContext();
final Attributes attributes = iDirC
.getAttributes("dns:/" + domainName, new String[] { "MX" });
final Attribute attributeMX = attributes.get("MX");
if (attributeMX == null) {
return new String[] { domainName };
}
final String[][] pvhn = new String[attributeMX.size()][2];
for (int i = 0; i < attributeMX.size(); i++) {
pvhn[i] = ("" + attributeMX.get(i)).split("\\s+");
}
// sort the MX RRs by RR value (lower is preferred)
Arrays.sort(pvhn, new Comparator<String[]>() {
public int compare(final String[] o1, final String[] o2) {
return Integer.parseInt(o1[0]) - Integer.parseInt(o2[0]);
}
});
// put sorted host names in an array, get rid of any trailing '.'
final String[] sortedHostNames = new String[pvhn.length];
for (int i = 0; i < pvhn.length; i++) {
sortedHostNames[i] = pvhn[i][1].endsWith(".") ? pvhn[i][1].substring(0, pvhn[i][1]
.length() - 1) : pvhn[i][1];
}
return sortedHostNames;
}
for example:
public static void main(String[] args) throws Exception {
// prints [gmail-smtp-in.l.google.com, alt1.gmail-smtp-in.l.google.com, alt2.gmail-smtp-in.l.google.com, alt3.gmail-smtp-in.l.google.com, alt4.gmail-smtp-in.l.google.com]
System.out.println(Arrays.asList(lookupMailHosts("gmail.com")));
}
so you would use "gmail-smtp-in.l.google.com" as your first choice for javax.mail:
Properties props = new Properties();
props.setProperty("mail.smtp.host", lookupMailHosts("gmail.com")[0]);
// ... other properies
Session smtpSession = Session.getInstance(props, null)
You could even combine this approach with a simple HTTP to SMTP kind of service hosted on AppEngine. All it would have to do is receive HTTP POST requests and forward them as an email using the method shown above.

Categories

Resources