Read a Environment Variable in Java with Websphere - java

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/..." );

Related

IBM websphere application server is giving me a null value from getinitparameter() and I cant figure out why

I have been tasked at work with fixing some other teams deployment into IBM Websphere
They use javax servletcontext to get values out of web.xml
I have read so many articles
sc is ServletContext passed in as a parameter
( I'm new to IBM websphere )
Enumeration<String> testParam = sc.getInitParameterNames();
while(testParam.hasMoreElements()) {
String value = testParam.nextElement();
sc.getInitParameter(value);
}
but I can do anything to web.xml and it sees no changes
I have tried adding
<Context-param>
and i have tried adding
<init-param>
and then searching by that param name directly which returns a null
also I have queried all the params using the pasted code example and it shows none of my test params
yet
also it has found a param by the name of "WELD_CONTEXT_ID_KEY" which translates to the value of the war but I used
Findstr /s /i "WELD_CONTEXT_ID_KEY" .
at the server root and that string only exists in the log from the code I created
I Have no idea what to do because I cant seem to affect change and I cant find that param name
PLEASE HELP***
For the benefit of anyone who comes across this problem in the future
I learned that the solution is to fix the web_merged.xml inside a different folder
as it turns out
Websphere takes the war and creates multiple iterations it looks like
leaving web.xml inside
[server name 1]\profiles[server name]\config\cells[cell name]\applications[\deployments\[application war]\[application war]\WEB-INF\
there you can find web_merged.xml
web.xml
and then you can find a copy of web.xml
inside
[server name 1]\profiles[server name 1]\installedApps[cell name][application war][application war]\WEB-INF\

Tomcat 7 - Get the application name during runtime without login via java-agent/aspectj

I'm trying to get a list of all deployed applications, and specifically the name of the application mapped to tomcat root.
I want to be able to do it during runtime, using a java agent that collects information on the tomcat server.
I tried using this code sample:
private Iterable<String> collectAllDeployedApps() {
try {
final Set<String> result = new HashSet<>();
final Set<ObjectName> instances = findServer()
.queryNames(new ObjectName("Tomcat:j2eeType=WebModule,*"), null);
for (ObjectName each : instances) {
result.add(substringAfterLast(each.getKeyProperty("name"), "/")); //it will be in format like //localhost/appname
}
return result;
} catch (MalformedObjectNameException e) {
//handle
}
}
taken from a similar question but since I'm not logged into the manager app, I don't have the right permissions, so I get an empty list.
What I actually want - I have a java agent (based on aspectJ), and I'd like during runtime/deployment time etc. to be able to get the list of all deployed apps without actually logging in to the manager myself.
How can I do this? I don't mind instrumenting tomcat's deployment code (which doesn't require any login from my side as I'm already instrumenting the code), but I'm not sure which function to instrument.
Thanks,
Lin
The question consists of 2 parts:
Get a list of all deployed applications - After reviewing Tomcat's API, I found several relevant deployment code parts which can be instrumented:
WarWatcher.java (allows to detect changes), and we can also see the apps from - UserConfig.java which is called on startup (instrumentation can be done on setDirectory name etc.), and of course HostConfig.java that is called on stratup:
protected void org.apache.catalina.startup.HostConfig.deployWARs(java.io.File, java.lang.String[])
protected void org.apache.catalina.startup.HostConfig.deployApps()
protected void org.apache.catalina.startup.HostConfig.deployWAR(org.apache.catalina.util.ContextName, java.io.File)
In addition - you can check the argument for:
protected boolean org.apache.catalina.startup.HostConfig.deploymentExists(java.lang.String)
It includes the war/folder name (which usually means the application name+-).
Get the root application name - This can be done by using ServletContext.getRealPath() - It returns the folder name, from which the war name can be extracted (and can be used, in my case at least as the app name).

JVM property in JAVA

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.

Running test for database adapter using main() Method

I have a problem in a system that I am working as back-end support for. I need to write a test that calls one of the classes handeling the communications with our database so I can log out what it actually returns.
System setup
Our system is developed in Java and deployed on a weblogic server. It consists of many parts that I will not go into detail on here. But the interesting part is that we have a class acting as an adapter for our database. We call it "CMAdapter" and it is an implementations of IBM Content Manager specific code to handle interaction with our database. In this class we have a methid called fetchAct() that take one object with search parameters as an argument and it returns the result of the search. In this case it returns one act. The code we have is running on a weblogic server, that has an IBM Information Integrator for Content installed so that it can communicate with IBM Content Manager that is installed and running on a different server. The system is deployed on the server using a .ejb and a few .jar files.
The problem
I have recieved a case stating that for some acts the users are not recieving the full act as expected but only parts of it. The system itself displays no errors and the documents are present in the database. So what I am trying to do is write a simple test program that calls this "CMAdapter" with a predetermined set of searchcriteria so that I may log out the return of the search.
My question
How can I make a freestading class with a main() method and run it on the server? I need to make a call to the CMAdapter.fetchAct() method in a way so it runs on the server like any normal query?
My test class
public class TestHamtaAkt
{
public static void main(String[] args) throws BasException
{
Log LOG = Log.getLog(TestHamtaAkt.class);
// Get the CMAdapter
CMAdapter cmadapter = new CMAdapter();
// Create empty instance of our query object
SokVO sokvo = new SokVO();
// Put a value to search for in our query object
AttributVO aktAttribut = new AttributVO();
aktAttribut.setNamn(DLAKonstanter.AKT_KORT_R_KOD);
aktAttribut.setVarde("090084831574");
sokvo.aktAttributLista().add(aktAttribut);
// do the search an recieve the answer
AktVO aktvo = cmadapter.hamtaAkt(sokvo);
// log out the result
LOG.debug("main", "Akten som hämtades: " + aktvo.toString(), null);
}
}
Thanks to all for reading my question. It appears I have found the answer to my own question. It was hiding with a collegue of mine. The answer to my problem was, to be able to access the server deployed code, I need to get the JNDI context from my webserver and from that do a jndi lookup for the class I need.
I still have some problems making the connection but that is problably just my configurations that are off. I now know how I get a simple java class to make a call to a deployed class on a server.
here is the code I am currently using to get the context from the WLS server:
private static InitialContext getWLSContext(String url) throws NamingException
{
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, WLS_CONTEXT_FACTORY);
//env.put(Context.PROVIDER_URL, "t3://" + host + ":" + port);
env.put(Context.PROVIDER_URL, url);
return new InitialContext(env);
}
This is my code for geting the class I need.
public static EJBObject getRemote(String url, String jndiname, Class homeClass, AppserverTyp typ) throws Exception
{
Object obj = getWLSContext(url).lookup(jndiname);
EJBHome home = (EJBHome) javax.rmi.PortableRemoteObject.narrow(obj, homeClass);
Class homeBase = home.getClass();
Method m = homeBase.getMethod("create", (Class[])null);
EJBObject remote = (EJBObject) m.invoke(home, (Object[])null);
return remote;
}
I hope this helps someone with a similar problem to move forward. Like I said I have still to actually get this code working for me but my this is the answer to my initial question on how to make a call to a deployed method from an external class.

Getting instance name of a WebSphere app Server

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

Categories