I have searched the Weblogic documentation extensively:
All the documentation on the Oracle site and all the examples I have found so far only show how to get a reference to this MBean via a Remote connection or to an instance of MBeanServer locally.
The little bit that mentions a local connection is vague and incomplete:
Absolute JNDI name of the MBean server. The JNDI name must start with
/jndi/ and be followed by one of the JNDI names described in Table
4-1.
Table 4-1 shows:
MBean Server JNDI Name
Domain Runtime MBean Server weblogic.management.mbeanservers.domainruntime
This doesn't work, I tried dumping the JNDI tree and can't find anything relevant in there.
I am on the AdminServer so that isn't the issue.
What I can find instructions to do that works is getting a reference to an instance of MBServer, but that isn't what I need; example: (MBeanServer) ctx.lookup("java:comp/env/jmx/domainRuntime");
But this doesn't do me any good, it is an instance of MBeanServer and I don't want to dig through all the indirection with the ObjectName stuff.
What I need to reference is DomainRuntimeServiceMBean interface:
What I need is to be able to get an instance of DomainRuntimeServiceMBean - JavaDoc
Short Answer
The type safe interfaces are all Deprecated, you have to do the lookup/tree walking manually.
As of 9.0, the MBeanHome interface and all type-safe interfaces for
WebLogic Server MBeans are deprecated. Instead, JMX applications that
interact with WebLogic Server MBeans should use standard JMX design
patterns in which clients use the
javax.management.MBeanServerConnection interface to discover MBeans,
attributes, and attribute types at runtime.
Long Answer
private InitialContext ctx;
private MBeanServer domain;
private ObjectName domainObjectName;
In the constructor:
ctx = new InitialContext();
this.domain = (MBeanServer) ctx.lookup("java:comp/env/jmx/domainRuntime");
this.domainObjectName = new ObjectName("com.bea:Name=DomainRuntimeService,Type=weblogic.management.mbeanservers.domainruntime.DomainRuntimeServiceMBean");
In your method:
final ObjectName dr = (ObjectName) this.domain.getAttribute(domainObjectName, "DomainRuntime");
final ObjectName dm = (ObjectName) this.domain.getAttribute(dr, "DeploymentManager");
final ObjectName[] adrs = (ObjectName[]) this.domain.getAttribute(dm, "AppDeploymentRuntimes");
for (final ObjectName on : adrs)
{
if (this.domain.getAttribute(on, "ApplicationName").equals(appName))
{
this.domain.invoke(on, "stop", null, null);
break;
}
}
Of course now I have to write my own convenience classes that are typesafe to wrap all this verbose non-sense!
Related
I am new to JNDI and i read the online material by oracle:
http://docs.oracle.com/javase/jndi/tutorial/getStarted/overview/index.html
It says JNDI has two API's viz:
1) JNDI API
2) JNDI SPI
Further, it says to use JNDI we should have JNDI classes as well as Service providers.
From what I understand, Service provider is the actual resource (naming or directory) e.g. LDAP or DNS (Is this my understanding correct)?
I have following doubts:
a) JNDI API: We write application and use JNDI API's to do lookup etc. Now, who does implement JNDI API? Are they complete implementation in itself i.e implemented by JDK providers themselves or by service providers?
b) JNDI SPI: what exactly is it? Are JNDI SPI specific to a service e.g. LDAP server? Who provides implementations of JNDI SPI. FYI i saw the source code of javax.naming.spi (among others) I saw there are some interface and some classes. And are these JNDI SPI's used in the application side (like If i am writing a simple application to do lookup from LDAP, so would this jar be in application)
Any help appreciated a lot.
EDIT:
Here is one simple JNDI program.
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class JNDIExample {
public static void main(String s[]) {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
// Is "com.sun.jndi.fscontext.RefFSContextFactory" the SPI API?
// What exactly is this?
Context ctx = new InitialContext(env);
try {
// Create the initial context
Context ctx = new InitialContext(env);
// Look up an object
Object obj = ctx.lookup(name);
// Print it
System.out.println(name + " is bound to: " + obj);
} catch (NamingException e) {
System.err.println("Problem looking up " + name + ": " + e);
}
}
}
With respect to above example, i have following doubts:
In this above example we are mainly using javax.naming.* stuff; who implements them?
Where is the SPI involved in this?
a) JNDI API: We write application and use JNDI API's to do lookup etc. Now, who does implement JNDI API? Are they complete implementation in itself i.e implemented by JDK providers themselves or by service providers?
By whoeveer has registered an ObjectFactory. In a JRE application this probably won't extend beyond the JRE itself. In a Servlet or J2EE container it will definitely extend to include the container itself, for java:comp resources, and possibly the Web-app itself as well.
b) JNDI SPI: what exactly is it?
It is a Service Provider Interface that service providers must implement.
Are JNDI SPI specific to a service e.g. LDAP server?
Yes.
Who provides implementations of JNDI SPI.
Almost entirely the JRE itself.
Are these JNDI SPI's used in the application side
They can be, at least as far as ObjectFactory, but it isn't usual.
(like If i am writing a simple application to do lookup from LDAP, so would this jar be in application)
No.
EDIT Re your new questions:
In this above example we are mainly using javax.naming.* stuff; who implements them?
The JRE, specifically the factory class you specified and its friends.
Where is the SPI involved in this?
The factory class and friends implement the SPI.
I'm trying to connect to EJB on WebSphere 7.0. The EJB requires javax.ejb.SessionContext and reads Principal from it, so I need to log in before calling it.
I'm using the following code in stand-alone application:
import javax.naming.InitialContext;
import javax.security.auth.login.LoginContext;
import com.ibm.websphere.security.auth.WSSubject;
import com.ibm.websphere.security.auth.callback.WSCallbackHandlerImpl;
public static void main(String[] args) throws Exception {
InitialContext ic = new InitialContext(System.getProperties());
LoginContext lc = new LoginContext("WSLogin",
new WSCallbackHandlerImpl("myuser","mypass"));
lc.login();
WSSubject.setRunAsSubject(lc.getSubject());
SessionContext sessionContext=(SessionContext) ic.lookup(
"java:comp/env/sessionContext");
}
I've added the entry to my jmxremote.access:
myuser readwrite
However, I get an exception:
Caused by: javax.naming.ConfigurationException: Name space accessor
for the java: name space has not been set. Possible cause is that the
user is specifying a java: URL name in a JNDI Context method call but
is not running in a J2EE client or server environment. at
com.ibm.ws.naming.java.javaURLContextFactory.isNameSpaceAccessable(javaURLContextFactory.java:98)
at
com.ibm.ws.naming.urlbase.UrlContextFactory.getObjectInstance(UrlContextFactory.java:82)
at
javax.naming.spi.NamingManager.getURLObject(NamingManager.java:584)
at
javax.naming.spi.NamingManager.getURLContext(NamingManager.java:533)
at
javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:320)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
What else should I do, to run my code in the 'J2EE client environment' mentionend in the error message?
In order to use java:comp, you would need to package the client application in an .ear and use launchClient. Ultimately, that's just going to use -CCBootstrapHost/-CCBootstrapPort (or defaults) to connect to the target server to look up the EJB, so you could just use the EJB thinclient and use the fully-qualified EJB binding name instead (see the CNTR0167I messages in SystemOut.log).
you'll need to use the WAS client runtime JARs. WAS_HOME/AppServer/runtimes. You will need the ORB and the other service specific JARs. As an alternative to using launchClient, you can manually specify the context factory you'll be using here:
InitialContext ic = new InitialContext(System.getProperties());
set the
java.naming.factory.initial
variable (in your system env or in a Properties object) to
com.ibm.websphere.naming.WsnInitialContextFactory`
I have a web-app in Java/Java EE deployed on any application server/web server. I would like to get all the datasources configured on this server in my application.
Does anyone have any ideas to achieve it? I can get those through WLST ant tasks. But I need to get them programatically.
If your datasources are configured with JNDI then you can list the context and can get all the names (more from here) with Context.list() method and from those name you can find all the datasources
the Context.list() returns an enumeration of NameClassPair. Each NameClassPair consists of the object's name and its class name. So just iterate it and check the class name for java.sql.DataSource and then get the object name to retrieve it.
With JBoss you can do the following (assuming JMX is available):
Context ctx = new InitialContext();
MBeanServerConnection mconn = (MBeanServerConnection)ctx.lookup("jmx/invoker/RMIAdaptor");
ObjectName name = new ObjectName("jboss.jca:service=DataSourceBinding,*");
Set s = mconn.queryMBeans(name, null);
Where s is an mbeans collection.
I'm trying to (unit) test my EJB class without having to startup my websphere environment. Now I'm using Open EJB, but there are some issues with resolving the JNDI Names for other EJBs that are used within my EJB... and there is no way for me to inject mocked classes from my test right now.
Getting the InitialContext
final Properties properties = new Properties();
properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
properties.setProperty("log4j.category.OpenEJB.options ", "debug");
properties.setProperty("log4j.category.OpenEJB.startup ", "debug");
properties.setProperty("log4j.category.OpenEJB.startup.config ", "debug");
properties.setProperty("MyOwnDatasource.JdbcDriver ", "com.ibm.as400.access.AS400JDBCDriver");
properties.setProperty("MyOwnDataSource.JdbcUrl ", "jdbc:as400:MYHOSTNAME;database name=MYDATABASE;libraries=MYDEFAULTTABLE");
ic = new InitialContext(properties);
Inside my class under test there is a lookup for java:comp/env/ejb/PrefixEjbNameLocalHome and I can not set Open EJB to generate JNDI names in that format.
Additional Property for JNDI name format
I tried setting the formatting rule like this:
properties.setProperty("openejb.jndiname.format ", "comp/env/ejb/{interfaceClass}");
Properties aren't used?
Also the logging configuration isn't used. I'm only seeing INFO and WARN messages from Open EJB, although I set log4j.category.OpenEJB.* and the like to DEBUG or TRACE.
It's the "java:" part that is messing up your test case. Basically Context.INITIAL_CONTEXT_FACTORY and "java:" are mutually exclusive. The InitialContext class has a special understanding of "java:" or any "foo:" lookups and if they are at the beginning of the name it will not use INITIAL_CONTEXT_FACTORY you specified. A somewhat frustrating part of JNDI.
If you lookup the name exactly as printed in the log, it will work. So for example this log message:
INFO - Jndi(name=WidgetBeanRemote) --> Ejb(deployment-id=WidgetBean)
Then in code:
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
// set any other properties you want
Context context = new InitialContext(p);
Object o = context.lookup("WidgetBeanRemote");
I'm having problems calling EJB3 stateless bean outside the container.
Code for getting the object reference:
Context envCtx = (Context) context.lookup("ejb");
MyObject o = (MyObject) envCtx.lookup(MyObject);
The second row results in exception:
java.lang.ClassCastException: javax.naming.Reference
I use JBoss.org 5.1.0 GA.
Based on some other posts I suspect this might be due to wrong version of client libraries. However, I'm unsure which library jar(s) I should include in the jar? (I get the error using 5.0.4.GA jnpserver.)
For JBoss, your code should look something like that:
Properties properties = new Properties();
properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
properties.put("java.naming.factory.url.pkgs","=org.jboss.naming:org.jnp.interfaces");
properties.put("java.naming.provider.url","localhost:1099");
Context context = new InitialContext(properties);
(EchoBeanRemote) c.lookup("EchoBean/remote");
If you prefer, you can put the JNDI environement settings in a jndi.properties file (that needs to be on the classpath):
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=jnp://localhost:1099
And use the non-arg InitialContext constructor:
Context context = new InitialContext();
(EchoBeanRemote) c.lookup("EchoBean/remote");
This is obviously more portable.
And in both case, you'll need jbossall-client.jar on the classpath on the client side.
P.S.: You can check the Global JNDI Name your bean is registered at in the JNDI View of the web-based JMX console (if it still exists).