Search code examples
javaglassfishinitial-context

How to get initial context from GlassFish server in Java SE?


I have a class like below:

public class Poligon {

    public static void main(String[] args) {

        try {
            Context ctx = new InitialContext();
            ConnectionFactory connectionFactory = (ConnectionFactory) ctx.lookup("jms/javaee7/ConnectionFactory");
            Destination destination = (Destination) ctx.lookup("jms/javaee7/Topic");
            JMSContext context = connectionFactory.createContext();
            OrderDTO order = context.createConsumer(destination).receiveBody(OrderDTO.class);
            System.out.println("Order received: " + order);
        } catch (NamingException ex) {
            Logger.getLogger(Poligon.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

I would like to get the InitialContext() form the server (glassfish) running on localhost, but I get the below error:

SEVERE: null
javax.naming.NoInitialContextException: Need to specify class name in environment or  system property, or as an applet parameter, or in an application resource file:  
    java.naming.factory.initial
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:662)
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307)
    at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:344)
    at javax.naming.InitialContext.lookup(InitialContext.java:411)
    at poligon.Poligon.main(Poligon.java:29)

I know I have to create ldap realm on glassfish and add the below code (? - dont know the exact values) to my class:

Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY,
            "?");
    env.put(Context.PROVIDER_URL, "?");
    env.put(Context.SECURITY_PRINCIPAL, "?");
    env.put(Context.SECURITY_CREDENTIALS, "?");

Context ctx = new InitialContext(env);

My problem is that I dont know what values should be at:

Context.INITIAL_CONTEXT_FACTORY
Context.PROVIDER_URL (I want it on localhost)
Context.SECURITY_PRINCIPAL
Context.SECURITY_CREDENTIALS

And I dont know how I should configure glassfish server?

enter image description here

maven dependencies

    <dependency>
        <groupId>org.glassfish.main.extras</groupId>
        <artifactId>glassfish-embedded-all</artifactId>
        <version>4.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.main.appclient.client</groupId>
        <artifactId>gf-client</artifactId>
        <version>3.1.2.2</version>
    </dependency>

Solution

  • In order to use JNDI you need to specify the java.naming.factory.initial somehow, just like the error message says.

    There are multiple ways of doing this:

    You could specify it as a system property in Glassfish, through server (Admin server) -> Properties

    Alternatively, you could specify it in a HashTable and pass it to the constructor of InitialContext:

    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY,  
        "com.sun.enterprise.naming.SerialInitContextFactory");
    
    Context ctx = new InitialContext(env);
    

    If you use Spring you could also do this:

    <bean id="myJndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
            <props>
                <prop key="java.naming.factory.initial">com.sun.enterprise.naming.SerialInitContextFactory</prop>
                <prop key="java.naming.factory.url.pkgs">com.sun.enterprise.naming</prop>
                <prop key="java.naming.factory.state">com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl</prop>
            </props>
        </property>
    </bean>
    

    See http://docs.oracle.com/javase/jndi/tutorial/beyond/env/context.html for more information.

    As far as the actual values go, the Spring config above is what we actually use with Glassfish. We do not specify provider url or credentials..

    I don't think this is really connected to creating an ldap-realm, Glassfish might use JNDI to lookup the realm though.

    Edit:

    I think I might understand what the problem is, you are trying to access remote classes from a client. With this assumption, you can use Spring to do this, with JndiTemplate. Assuming that the server makes available the correct EJB-classes, do this on the client side:

    Create a bean for JndiTemplate:

      <bean id="myJndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
          <props>
            <prop key="java.naming.factory.initial">com.sun.enterprise.naming.SerialInitContextFactory</prop>
            <prop key="org.omg.CORBA.ORBInitialHost">${servername}</prop>
            <prop key="org.omg.CORBA.ORBInitialPort">${jndiport}</prop>
          </props>
        </property>
      </bean>
    

    You can then use this bean to lookup stuff on the server. If you want to take it a step further, and call your own remote EJB-classes, you could also do this:

      <bean id="ejbProxy"
            class="org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean"
            abstract="true">
        <property name="refreshHomeOnConnectFailure" value="true"/>
        <property name="cacheHome" value="true"/>
        <property name="lookupHomeOnStartup" value="true"/>
        <property name="resourceRef" value="false"/>
        <property name="jndiTemplate" ref="mySpringTemplate"/>
      </bean>
    

    And then define beans as:

      <bean id="someRemoteService" parent="ejbProxy">
        <property name="jndiName"
                  value="com.company.service.MyRemoteService"/>
        <property name="businessInterface"
                  value="com.company.service.MyRemoteService"/>
      </bean>
    

    You can inject this like a regular bean, any calls to it will be made to the server.