My Web service will run on a Jboss App Server or a Websphere app Server. For both of them I need to know the instance name, for Jboss I can use System.getProperty("jboss.server.name"), but what can I use for WebSphere? I can't use WebSphere-specific methods, I need to call System.properties
Thanks
An alternative, at least for WebSphere, is to look it up in the JNDI tree.
This is what I use:
InitialContext ic = new javax.naming.InitialContext();
String serverName = ic.lookup("servername").toString();
This way I don't have to configure anything as WebSphere binds that information for me.
Cell and node name can also be retrieved using "thisNode/cell/cellname" and "thisNode/nodename". Something useful in clusters.
I agree with specifying server name as an environment variable (Manglu's touch is also fine). Just to make the discussion complete, here is how you get get instance name via runtime (this API is deprecated in recent versions but still in use);
import com.ibm.websphere.runtime.ServerName;
System.out.println("Display name: " + ServerName.getDisplayName());
System.out.println("Full name: " + ServerName.getFullName());
Sample output would be like
Display name: server1
Full name: was7host01Node01Cell\was7host01Node01\server1
To keep it platform neutral you can set a variable as a JVM argument for the Websphere server (one for each node if its clustered). For Websphere 7, you will find the following in the Admin Console ...
Servers > Server Types > Websphere application servers > [your cluster node] >
> Java and Process Management > Process Definition > Java Virtual Machine >
> Generic JVM arguments
and add a variable like this ...
-DServerName=serverNodeA
You can then access the value in your code as ...
String serverName = System.getproperty("ServerName");
This technique can be used with all application servers so long as you have access to add arguments to the JVM. I'm sure there must be Websphere specific API to query the node name, but then you're typing your code to the server which makes it difficult to unit test and is not portable. I prefer this approach.
kurtcebe solution works well. For those using maven, you won't be able to get the jar easily into your project. Because of this, use Class.forname...
try {
Class<?> c = Class.forName("com.ibm.websphere.runtime.ServerName");
LOGGER.debug("Class found" + c);
Method m = c.getMethod("getFullName", new Class<?>[0]);
LOGGER.debug("Method found" + m);
Object o = m.invoke(DeliveryServiceUtils.class, new Object[0]);
LOGGER.debug("Method invoked, response is " + o);
processName = o.toString();
}
catch (Exception ex) {
processName = "unknown - " + ex.getClass().getName() + ": " + ex.getMessage();
}
The approach suggested by Brad is good but I would do it subtle differently.
In the custom property of the Server JVM, I would add a property Server-Name and specify its value as WAS_SERVER_NAME.
here is the bread crumb for this:
Servers -> -> Process Definition -> Java Virtual Machine > Custom properties
Add a new one wiht say ServerName with value ${WAS_SERVER_NAME}
Every WAS Server instance has this WebSphere Variable set to the name of the Server instance. You don't need to worry about making typos (or similar errors here) and this approach works for all WAS Server.
You can create a Server with such values set as a template and when you create a new server, these are always present for you.
HTH
Related
A scenario - an EAR is installed on Websphere app server and running at more than 30 JVMs. I want to create a property only at one JVM and want to read that in my java code.
How can i create a JVM level property by WAS console and read it in Java.
Creating custom propery
In WAS (server1) or the deployment manager admin console, navigate to
Servers > ServerTypes > WebSphere application servers cutom property
And Click on the JVM on which you want to create the
Server Infrastructure (section) > Java and Process Management > Process definition
Additional Properties (section) > Java Virtual Machine > Cutom Properties
Click the ‘New’ button to add a new custom property.
Click ‘Apply’.
Click ‘Save’ directly to the master configuration.
In a stand-alone or single node environment, you need to stop and restart your server for the changes to take effect.
In a clustered environment, where you defined the property in the deployment manager, you’ll probably want to do a ‘full resynchronize’ and restart the cluster.
Accessing through Java code
After defining custom property within a WebSphere Application server or node where you defined the property, you can access its value just like you would a system property in Java, like this:
String custProperty = System.getProperty("wbe.home");
You can similarly use a scriptlet in a JSP page like this:
<%
String custProperty = System.getProperty("wbe.home");
if ( custProperty .equalsIgnoreCase("home") ) {
%>
If you want to automate the manual task of adding custom property to 30 JVM's
You can use Jython script . You can modify according to your requirement.
server = sys.argv[0]
property = sys.argv[1]
value = sys.argv[2]
if (len(sys.argv) == 4):
descr = sys.argv[3]
else :
descr = None
# Convert a list of items separated by linefeeds into an array
def getListArray(l):
return l.splitlines()
# Obtain the "simple" server name
def getServerName(s):
return AdminConfig.showAttribute(s, 'name')
# Add common attr list to specified Server's JVM
def addPropertiesToServer(s):
jvm = AdminConfig.list('JavaVirtualMachine', s)
# Look for existing property so we can replace it (by removing it first)
currentProps = getListArray(AdminConfig.list("Property", jvm))
for prop in currentProps:
if property == AdminConfig.showAttribute(prop, "name"):
print "Removing existing property from Server %s" % getServerName(s)
AdminConfig.remove(prop)
# Store new property in 'systemProperties' object
print "Adding property to Server %s" % getServerName(s)
AdminConfig.modify(jvm,[['systemProperties',attr]])
# Construct list with new property name and value
attr = []
if (descr is None):
print "Adding property %s=%s" % (property,value)
attr.append([['name',property],['value',value]])
else:
print "Adding property %s=%s,%s" % (property,value,descr)
attr.append([['name',property],['value',value],['description',descr]])
# Locate all Application Servers if server is 'all'
if (server == 'all'):
servers = AdminConfig.list('Server')
for aServer in getListArray(servers):
type = AdminConfig.showAttribute(aServer,'serverType')
if (type == 'APPLICATION_SERVER'):
addPropertiesToServer(aServer)
# TODO: support comma-separated list of servers
else:
# Locate specified Server and its JVM
server = AdminConfig.getid('/Server:'+server+'/')
addPropertiesToServer(server)
# Save changes
if (AdminConfig.hasChanges()):
AdminConfig.save()
You can create the WebSphere Variable at the cluster level on which your servers are running from:
Environment --> WebSphere Variable --> <SelectYour_cluster_From_Dropdown> --> New
Say, if, the variable name is "MY.CUSTOM.PROPERTY" then you can access it in your java code by writing following code:
String myCustomProperty = (String) System.getenv("MY.CUSTOM.PROPERTY");
Hope this works for you.
Which of the following is the best and most portable way to get the hostname of the current computer in Java?
Runtime.getRuntime().exec("hostname")
vs
InetAddress.getLocalHost().getHostName()
Strictly speaking - you have no choice but calling either hostname(1) or - on Unix gethostname(2). This is the name of your computer. Any attempt to determine the hostname by an IP address like this
InetAddress.getLocalHost().getHostName()
is bound to fail in some circumstances:
The IP address might not resolve into any name. Bad DNS setup, bad system setup or bad provider setup may be the reason for this.
A name in DNS can have many aliases called CNAMEs. These can only be resolved in one direction properly: name to address. The reverse direction is ambiguous. Which one is the "official" name?
A host can have many different IP addresses - and each address can have many different names. Two common cases are: One ethernet port has several "logical" IP addresses or the computer has several ethernet ports. It is configurable whether they share an IP or have different IPs. This is called "multihomed".
One Name in DNS can resolve to several IP Addresses. And not all of those addresses must be located on the same computer! (Usecase: A simple form of load-balancing)
Let's not even start talking about dynamic IP addresses.
Also don't confuse the name of an IP-address with the name of the host (hostname). A metaphor might make it clearer:
There is a large city (server) called "London". Inside the city walls much business happens. The city has several gates (IP addresses). Each gate has a name ("North Gate", "River Gate", "Southampton Gate"...) but the name of the gate is not the name of the city. Also you cannot deduce the name of the city by using the name of a gate - "North Gate" would catch half of the bigger cities and not just one city. However - a stranger (IP packet) walks along the river and asks a local: "I have a strange address: 'Rivergate, second left, third house'. Can you help me?" The local says: "Of course, you are on the right road, simply go ahead and you will arrive at your destination within half an hour."
This illustrates it pretty much I think.
The good news is: The real hostname is usually not necessary. In most cases any name which resolves into an IP address on this host will do. (The stranger might enter the city by Northgate, but helpful locals translate the "2nd left" part.)
In the remaining corner cases you must use the definitive source of this configuration setting - which is the C function gethostname(2). That function is also called by the program hostname.
InetAddress.getLocalHost().getHostName() is the more portable way.
exec("hostname") actually calls out to the operating system to execute the hostname command.
Here are a couple other related answers on SO:
Java current machine name and logged in user?
Get DNS name of local machine as seen by a remote machine
EDIT: You should take a look at A.H.'s answer or Arnout Engelen's answer for details on why this might not work as expected, depending on your situation. As an answer for this person who specifically requested portable, I still think getHostName() is fine, but they bring up some good points that should be considered.
As others have noted, getting the hostname based on DNS resolution is unreliable.
Since this question is unfortunately still relevant in 2018, I'd like to share with you my network-independent solution, with some test runs on different systems.
The following code tries to do the following:
On Windows
Read the COMPUTERNAME environment variable through System.getenv().
Execute hostname.exe and read the response
On Linux
Read the HOSTNAME environment variable through System.getenv()
Execute hostname and read the response
Read /etc/hostname (to do this I'm executing cat since the snippet already contains code to execute and read. Simply reading the file would be better, though).
The code:
public static void main(String[] args) throws IOException {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
System.out.println("Windows computer name through env:\"" + System.getenv("COMPUTERNAME") + "\"");
System.out.println("Windows computer name through exec:\"" + execReadToString("hostname") + "\"");
} else if (os.contains("nix") || os.contains("nux") || os.contains("mac os x")) {
System.out.println("Unix-like computer name through env:\"" + System.getenv("HOSTNAME") + "\"");
System.out.println("Unix-like computer name through exec:\"" + execReadToString("hostname") + "\"");
System.out.println("Unix-like computer name through /etc/hostname:\"" + execReadToString("cat /etc/hostname") + "\"");
}
}
public static String execReadToString(String execCommand) throws IOException {
try (Scanner s = new Scanner(Runtime.getRuntime().exec(execCommand).getInputStream()).useDelimiter("\\A")) {
return s.hasNext() ? s.next() : "";
}
}
Results for different operating systems:
macOS 10.13.2
Unix-like computer name through env:"null"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:""
OpenSuse 13.1
Unix-like computer name through env:"machinename"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:""
Ubuntu 14.04 LTS
This one is kinda strange since echo $HOSTNAME returns the correct hostname, but System.getenv("HOSTNAME") does not:
Unix-like computer name through env:"null"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:"machinename
"
EDIT: According to legolas108, System.getenv("HOSTNAME") works on Ubuntu 14.04 if you run export HOSTNAME before executing the Java code.
Windows 7
Windows computer name through env:"MACHINENAME"
Windows computer name through exec:"machinename
"
Windows 10
Windows computer name through env:"MACHINENAME"
Windows computer name through exec:"machinename
"
The machine names have been replaced but I kept the capitalization and structure. Note the extra newline when executing hostname, you might have to take it into account in some cases.
InetAddress.getLocalHost().getHostName() is better (as explained by Nick), but still not very good
One host can be known under many different hostnames. Usually you'll be looking for the hostname your host has in a specific context.
For example, in a web application, you might be looking for the hostname used by whoever issued the request you're currently handling. How to best find that one depends on which framework you're using for your web application.
In some kind of other internet-facing service, you'll want the hostname your service is available through from the 'outside'. Due to proxies, firewalls etc this might not even be a hostname on the machine your service is installed on - you might try to come up with a reasonable default, but you should definitely make this configurable for whoever installs this.
Although this topic has already been answered there's more to say.
First of all: Clearly we need some definitions here. The InetAddress.getLocalHost().getHostName() gives you the name of the host as seen from a network perspective. The problems with this approach are well documented in the other answers: it often requires a DNS lookup, it's ambiguous if the host has multiple network interfaces and it just plain fails sometimes (see below).
But on any OS there's another name as well. A name of the host that gets defined very early in the boot process, long before the network is initialized. Windows refers to this as computername, Linux calls it kernel hostname and Solaris uses the word nodename. I like best the word computername, so I'll use that word from now on.
Finding the computername
On Linux/Unix the computername is what you get from the C function gethostname(), or hostname command from shell or HOSTNAME environment variable in Bash-like shells.
On Windows the computername is what you get from environment variable COMPUTERNAME or Win32 GetComputerName function.
Java has no way of obtaining what I've defined as 'computername'. Sure, there are workarounds as described in other answers, like for Windows calling System.getenv("COMPUTERNAME"), but on Unix/Linux there's no good workaround without resorting to JNI/JNA or Runtime.exec(). If you don't mind a JNI/JNA solution then there's gethostname4j which is dead simple and very easy to use.
Let's move on with two examples, one from Linux and one from Solaris, which demonstrate how you can easily get into a situation where you cannot obtain the computername using standard Java methods.
Linux example
On a newly created system, where the host during installation has been named as 'chicago', we now change the so-called kernel hostname:
$ hostnamectl --static set-hostname dallas
Now the kernel hostname is 'dallas', as evident from the hostname command:
$ hostname
dallas
But we still have
$ cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 chicago
There's no misconfiguration in this. It just means the host's networked name (or rather the name of the loopback interface) is different from the host's computername.
Now, try executing InetAddress.getLocalHost().getHostName() and it will throw java.net.UnknownHostException. You are basically stuck. There's no way to retrieve neither the value 'dallas' nor the value 'chicago'.
Solaris example
The example below is based on Solaris 11.3.
The host has deliberately been configured so that the loopback name <> nodename.
In other words we have:
$ svccfg -s system/identity:node listprop config
...
...
config/loopback astring chicago
config/nodename astring dallas
and the contents of /etc/hosts :
:1 chicago localhost
127.0.0.1 chicago localhost loghost
and the result of the hostname command would be:
$ hostname
dallas
Just like in the Linux example a call to InetAddress.getLocalHost().getHostName() will fail with
java.net.UnknownHostException: dallas: dallas: node name or service name not known
Just like the Linux example you are now stuck. There's no way to retrieve neither the value 'dallas' nor the value 'chicago'.
When will you really struggle with this?
Very often you'll find that InetAddress.getLocalHost().getHostName() will indeed return a value which is equal to the computername. So there's no problem (except for the added overhead of name resolution).
The problem arises typically within PaaS environments where there's a difference between computername and the name of the loopback interface. For example people report problems in Amazon EC2.
Bug/RFE reports
A bit of searching reveals this RFE report : link1, link2. However, judging from the comments on that report the issue seems to have been largely misunderstood by the JDK team, so it is unlikely it will be addressed.
I like the comparison in the RFE to other programming languages.
Just one-liner ... cross platform (Windows-Linux-Unix-Mac(Unix)) [Always works, No DNS required]:
String hostname = new BufferedReader(
new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream()))
.readLine();
You're done !!
Environment variables may also provide a useful means -- COMPUTERNAME on Windows, HOSTNAME on most modern Unix/Linux shells.
See: https://stackoverflow.com/a/17956000/768795
I'm using these as "supplementary" methods to InetAddress.getLocalHost().getHostName(), since as several people point out, that function doesn't work in all environments.
Runtime.getRuntime().exec("hostname") is another possible supplement. At this stage, I haven't used it.
import java.net.InetAddress;
import java.net.UnknownHostException;
// try InetAddress.LocalHost first;
// NOTE -- InetAddress.getLocalHost().getHostName() will not work in certain environments.
try {
String result = InetAddress.getLocalHost().getHostName();
if (StringUtils.isNotEmpty( result))
return result;
} catch (UnknownHostException e) {
// failed; try alternate means.
}
// try environment properties.
//
String host = System.getenv("COMPUTERNAME");
if (host != null)
return host;
host = System.getenv("HOSTNAME");
if (host != null)
return host;
// undetermined.
return null;
The most portable way to get the hostname of the current computer in Java is as follows:
import java.net.InetAddress;
import java.net.UnknownHostException;
public class getHostName {
public static void main(String[] args) throws UnknownHostException {
InetAddress iAddress = InetAddress.getLocalHost();
String hostName = iAddress.getHostName();
//To get the Canonical host name
String canonicalHostName = iAddress.getCanonicalHostName();
System.out.println("HostName:" + hostName);
System.out.println("Canonical Host Name:" + canonicalHostName);
}
}
If you're not against using an external dependency from maven central, I wrote gethostname4j to solve this problem for myself. It just uses JNA to call libc's gethostname function (or gets the ComputerName on Windows) and returns it to you as a string.
https://github.com/mattsheppard/gethostname4j
hostName == null;
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
{
while (interfaces.hasMoreElements()) {
NetworkInterface nic = interfaces.nextElement();
Enumeration<InetAddress> addresses = nic.getInetAddresses();
while (hostName == null && addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (!address.isLoopbackAddress()) {
hostName = address.getHostName();
}
}
}
}
Building off of Dan Ortega's answer, I created a generic executeCommand(String) method that takes a command as a paramater.
import java.io.*;
public class SystemUtil {
public static void main(String[] args) throws IOException {
System.out.println(retrieveHostName());
}
public static String retrieveHostName() throws IOException {
return executeCommand("hostname");
}
private static String executeCommand(String command) throws IOException {
return new BufferedReader(
new InputStreamReader(Runtime.getRuntime().exec(command).getInputStream()))
.readLine();
}
}
InetAddress.getLocalHost().getHostName() is the best way out of the two as this is the best abstraction at the developer level.
I've a little problem with Websphere application server 7.0 (WAS7) and the reading of Environment Varaibles.
With TomCat, I've defined a variable as
<Environment name="myVar" type="java.lang.String" value="myVarOnServeur"
and I read it with a lookup on the initialContext :
Context ctx = new InitialContext();
String myVar = (String) ctx.lookup( "java:comp/env/myVar" );
and it works!
But with Websphere, I define a environment variable on the GUI but I can't read it in my java code. I've a NamingException.
(source: fullahead.org)
How can I do to fix my problem?
to define inside web.xml
<env-entry>
<env-entry-name>varName</env-entry-name>
<env-entry-value>56</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
to see with java
Context envEntryContext = (Context) new InitialContext().lookup("java:comp/env");
String mydata = (String)envEntryContext.lookup("varName");
You are looking at the wrong place.
You should add the variable in Environment->Naming->Name space bindings->New.
If you choose Binding type String, "Binding identifier" and "Name in namespace..." myVar, you can get variable's value with:
Context ctx = new InitialContext();
String myVar = (String) ctx.lookup( "cell/persistent/myVar" );
On WAS follow the above setting where name is your key and value is your property value. in my example i used Name : Test Value : This is the test value. After setting this values restart your application server. on your Java code call System.getProperty("TEST") where test is the name for your property and the value will show
You can put something like the following in your web.xml file, which should be in your application's WEB-INF directory:
<env-entry>
<env-entry-name>myVar</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>myVarOnServeur</env-entry-value>
</env-entry>
By the way this is a standard syntax and should work across all the application servers. I'm using it with WebSphere, JBoss and WebLogic. It can be queried exactly as you do in your example.
If what you want is to define and manage your own variables, have a look at Environment->Naming->Name space bindings. You can bind jndi names to String constants there. see String binding settings
You should be able to resolve these via WebSphere's AdminOperations MBean:
//sample code from WAS 7 Infocenter
private String expandVariable(String s) throws
javax.management.JMException {
com.ibm.websphere.management.AdminService as =
com.ibm.websphere.management.AdminServiceFactory.getAdminService();
String server = as.getProcessName();
String mBeanName = "*:*,type=AdminOperations,process=" + server;
java.util.Set result = as.queryNames(
new javax.management.ObjectName(mBeanName) , null);
return (String) as.invoke((javax.management.ObjectName)
result.iterator().next(),
"expandVariable",
new Object[]{"${"+s+"}"},
new String[]{"java.lang.String"});
}
See Creating, editing and deleting WebSphere variables.
Websphere 7.0 - 8.5
Set Variable
Admin Console ---> Websphere Application servers -----> Your_sever_name ---> Java and process management ---> Process definition -->Java Virtual Machine --> Custom properties
Get Value in Java
System.getProperty("Your_Variable")
I would just like to elaborate on creating a variable in WebSphere that can be used by a Java app, to hopefully help others, as I had to do a bit of additional research to figure this out.
Let's say you want to create a variable in WebSphere named ENV which contains a value of dev (or int, or prod, or any other value).
In the left panel of the WebSphere admin console, select Servers >
Server Types > WebSphere application servers.
Select the application server that contains the app.
Expand Java and Process Management and select process definition.
Select Java Virtual Machines.
Select Custom properties.
Select New.
Create the name and value of the variable and select OK.
Select Save.
Restart the application server for this change to take effect.
In this example, a variable named ENV with a vaule of "dev" was created.
Next, the Java app will need to be configured to use the ENV variable in WebSphere. In the below markup, the Java app has a class named "Environment". This class creates a variable named env. System.getProperty("ENV") is the magic that gets the variable from WebSphere. It is noteworthy that this Java code should also work with other application servers, such as JBoss or Tomcat, so you don't need to customize the Java code to a particular platform.
While definitely not required, I also am returning env. I am just doing this for demonstration, so that we can get the variable in a JSP page, so that we can see the variables with our own eyes in a JSP page, for validation that this works as expected.
package com.example.main;
public class Environment {
public String env;
public Environment() {
env = System.getProperty("ENV");
}
public String getEnvironment(){
return env;
}
}
Inside of the tags of a JSP page, I add the following markup to get the env variable from the Environment class, which in turn gets the ENV variable from WebSphere.
<%#page import="com.sample.main.Environment"%>
<%
Environment foo = new Environment();
String env = foo.getEnvironment();
out.print("Environment : " + env;
%>
Now, once the app has been deployed to WebSphere, the environment should be displayed, which is how I know that I was able to successfully get the variable from the application server.
The thread is kind of old but just wanted to provide some info. This is with WebSphere 8.5.5
I tried getting WebSphere variables defined in the console via [Environment > WebSphere variables] using
System.getProperty("Variable");
It did not give the variable to me. I looked around a bit on the web and came across the following:
https://www.setgetweb.com/p/WAS855/ae/was2873.html
The following function listed there returns the variables
private static String expandVariable(String s) throws
javax.management.JMException
{
com.ibm.websphere.management.AdminService as = com.ibm.websphere.management.AdminServiceFactory.getAdminService();
String server = as.getProcessName();
java.util.Set result = as.queryNames(new javax.management.ObjectName("*:*,"
+ "type=AdminOperations,process=" + server), null);
return (String)as.invoke((javax.management.ObjectName) result.iterator().next(),"expandVariable",
new Object[] {"${"+s+"}"}, new String[] {"java.lang.String"});
}
Then call
expandVariable("Variable");
I don't see anything there that says that those entries can be read via ctx.lookup( "java:comp/env/..." );
Is it possible to get a list of agents loaded into the current JVM by the Java 1.6 attach api? If so how?
Agents loaded at launch can be determined via RuntimeMXBean but I can't see a way to get a handle on ones added after launch.
(This question is similar to How to find list of java agents attached with a running JVM?. For the sake of completeness, I will add this answer to both questions.)
Checking agents that have been added using the Attach API:
If you are interested in the agents that have been added to an application at run time using the Attach API, you can use the DiagnosticCommandMBean.
This bean offers a diagnostic command called vmDynlib, a parameterless method that returns a String that list all dynamically loaded libraries.
Here is a snippet that prints all dynamic libraries loaded by the application's VM:
ObjectName diagnosticsCommandName = new ObjectName("com.sun.management:type=DiagnosticCommand");
String operationName = "vmDynlibs";
String result = (String) ManagementFactory.getPlatformMBeanServer().invoke(diagnosticsCommandName, operationName, null, null);
System.out.println(result);
This results in an output similar to this one:
Dynamic libraries:
0x00007ff7b8600000 - 0x00007ff7b8637000 C:\Program Files\Java\jdk1.8.0_181\bin\java.exe
0x00007ffdfeb00000 - 0x00007ffdfecf0000 C:\WINDOWS\SYSTEM32\ntdll.dll
0x00007ffdfe300000 - 0x00007ffdfe3b2000 C:\WINDOWS\System32\KERNEL32.DLL
0x00007ffdfbb30000 - 0x00007ffdfbdd3000 C:\WINDOWS\System32\KERNELBASE.dll
0x00007ffdfe950000 - 0x00007ffdfe9f3000 C:\WINDOWS\System32\ADVAPI32.dll
...
You can then check this text if it contains a certain .so or .dll file.
The same inspection can be performed non-programatically.
For this, you can use the jconsole tool.
Connect to a VM, switch to the tab MBeans, select com.sun.management, select DiagnosticCommand, select Operations, select vmDynlibs, and invoke it.
In the image, you can see one of my test agents attached to the application.
The agent was attached using the Attach API, thus this agent would not be visible by checking the application's command line arguments (i.e., no -agentpath=... would be seen on the arguments) but is only visible as dynamically loaded library.
Checking agents that have been added via command-line:
To have the complete reference, I will also post how to detect agents that have been added via the command line.
You can check them by using the RuntimeMXBean.
This bean offers the method getInputArguments, which returns a list of all VM arguments.
You can iterate over the list and check it for the arguments agentpath, agentlib and javaagent, similar to the following code snippet:
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
List<String> jvmArgs = runtimeMXBean.getInputArguments();
System.out.println("JVM arguments:");
for (String arg : jvmArgs) {
if (arg.startsWith("-agentpath") || arg.startsWith("-agentlib") || arg.startsWith("-javaagent")) {
System.out.print("***** ");
}
System.out.print(arg);
if (arg.startsWith("-agentpath") || arg.startsWith("-agentlib") || arg.startsWith("-javaagent")) {
System.out.println(" *****");
} else {
System.out.println();
}
}
No, I don't think there is a portable way to find out about the agents. What are you trying to accomplish? Maybe there is another approach...
Both the systems described are Windows XP with Lotus Notes 8.5.
I have a Java app (sample code below) that uses notes.jar to interact with Lotus Notes. The app works fine on a system that has notes.ini in the Lotus install dir of c:\Program Files\Lotus\Notes and the user ID file is in c:\Program Files\Lotus\Notes\Data. The user has to type a password to login to Lotus. This system has HKLM\Software\Lotus\Notes\MultiUser set to 0 (single user system). On this machine, the below code displays good values on the four println’s.
On a problem system, this app prints the four headings but blanks for the four values (the user name, key filename, mailfile, and mailserver are all blank). This problem system has notes.ini and the user ID file in D:\Data\johnsmith\NotesData. Lotus is installed in C:\Program Files\Lotus\Notes. This problem system also has HKLM\Software\Lotus\Notes\MultiUser set to 1 (implying it is multiuser instead of single user). Finally, under Lotus’s File -> Security -> User Security dialog the "Log in to Notes using your operating system login" box is checked (so the user doesn’t type in a password to login to Lotus).
So, it appears that on the problem system, the notes.ini file can’t be found (since notes.ini is where the four output values are supposed to be read from). I’ve looked through the Notes.jar API and can’t see any way to specify the location of notes.ini. The dir where notes.ini resides is in the Windows PATH, but that doesn’t help.
Any help would be appreciated.
import java.io.*;
import lotus.domino.*;
public static void main(String[] args) throws IOException {
try {
NotesThread.sinitThread();
Session session = NotesFactory.createSession();
System.out.println("Common user name: " + session.getCommonUserName());
System.out.println("KeyFilename: " + session.getEnvironmentString("KeyFilename", true));
System.out.println("MailFile: " + session.getEnvironmentString("MailFile", true));
System.out.println("MailServer: " + session.getEnvironmentString("MailServer", true));
} catch (Exception ex) {
ex.printStackTrace();
} finally {
NotesThread.stermThread();
}
}
As mentioned in the original question, if HKEY_LOCAL_MACHINE\Software\Lotus\Notes\MultiUser has a value of 1, then you have a multi-user installation (even if you are the only user of Lotus).
Here is a solution that worked. Find the location of Notes.ini, probably somewhere like C:\Documents and Settings\(username)\Lotus. Edit or create the string value below and set it to your Notes.ini directory. HKEY_CURRENT_USER\Software\Lotus\Notes\(optional-version)\NotesIniPath.
In a multi-user environment, Lotus Notes gets the ini filename from the NotesIniPath registry value.
Add a new command-line parameter, "=c:\data\johnsmith\NotesData\notes.ini" . To make this happen, you need to use NotesFactory.CreateSession(String host, String args[], String user, String passwd); method, after setting up a new String array containing that parameter and whatever other arguments were passed, since itis basically supposed to be the String args[] as passed to static Main. (The =fullpath\notes.ini parameter just needs to be in the array, it doesn't need to be in any specific location.)
This permits the session to be initialized with the absolute path to the notes.ini file used, and appears to be supported since (though I could be wrong) Notes 5.0.5.
Notably, the Directory= line is going to be taken from that notes.ini and used for all error reporting and logging, as the user's private data directory.
There is a number of things you can try:
Notes actually comes with its own JVM and I found using this JVM makes Java applications run more reliably with Notes classes since any eventually needed support library would be properly configured.
What happens if notes is already running before you start your program. There are 2 variations here: Checkbox "Don't prompt for a password from other Notes-based programs" is checked or unchecked.
Make sure to switch to the directory where the Notes.ini is at home before you run the app. (And verify that the user can't see any other notes.ini variables)