The Holy Java

Building the right thing, building it right, fast

Archive for April, 2006

Eclipse: Run => NoClassDefFoundError for an interface when loading a class implementing it

Posted by Jakub Holý on April 21, 2006

I had quite a hard time trying to run the following code in Eclipse (CollectionUserType implements UserType):

Class.forName("net.sf.hibernate.tap.CollectionUserType");

The problem was:

Exception in thread “main” java.lang.NoClassDefFoundError: net/sf/hibernate/UserType
    at java.lang.ClassLoader.findBootstrapClass(Native Method)
    at java.lang.ClassLoader.findBootstrapClass0(ClassLoader.java:891)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)

The strange thing was that I could define instances of both UserType and CollectionUserType so it was clear that the classes are available. The evident conclusion was that CollectionUserType  is loaded by a special classloader that doesn’t have access to UserType.

Examining closely the Run Configuration I’ve discovered the cause: the location of CollectionUserType was among the Bootstrap Entries while the location of UserType was among User Entries. And since the bootstrap class loader is above other class loaders in the class loader hierarchy, it has no access to classes loaded by the subordinate class loaders (including UserType) while vice versa it’s all right.<

So the solution was to move the entry from Bootstrap Entries to User Entries.

Posted in Languages | Tagged: , | Comments Off

Redeploy an application (ear/war/…) on JBoss

Posted by Jakub Holý on April 12, 2006

A) Via JMX-console

  1. find jboss.system:service=MainDeployer
  2. invoke listDeployed – find something like:
    org.jboss.deployment.DeploymentInfo@d78e875f { url=file:/C:/jboss-3.2.3/server/default/deploy/tap.ear } 
  3.   copy the url, go back and invoke Redeploy with the url (file:/C:/…) as the parameter.

B) From the command line

The operations that can be invoked via the JBoss JMX console can also be invoked by the cmd line client <jboss home>/bin/twiddle.

C) Manually

Modify application.xml (or web.xml for .war) of the application if deployed in the expload mode (or modify/touch/ the .ear?)

Posted in j2ee | Tagged: , , , | Comments Off

Access EJB on JBoss from outside

Posted by Jakub Holý on April 10, 2006

How to acces an enterprise java bean (EJB) running on JBoss from a standalone application running outside JBoss?

  1. In the code you must, among others:
    1. Set properties for a naming context and create one to be able to look the EJB up
    2. Authenticate by JBoss by means of JAAS
  2. To run the application:
    1. Set the classpath (-cp …): it must contain jbosssx.jar (ClientLoginModule), jboss-common.jar and jnpserver.jar (naming stuff) from <jboss home>/server/default/lib
    2. Create the JAAS configuration file sample_jaas.config containing:
      jboss_jaas { org.jboss.security.ClientLoginModule required; };
      

      If you ever wanted to run the application from JBoss, replace the JAAS config file by the following entry in <JBoss home>/server/default/conf/login-config.ml (application-policy name must be the same name as the one passed to the constructor of a LoginContext):

      <application-policy name = "tap_experiments">
             <authentication>
                <login-module code = "org.jboss.security.ClientLoginModule"  flag = "required"></login-module>
             </authentication>
          </application-policy>
      
    3. Pass the file to the JVM: -Djava.security.auth.login.config=sample_jaas.config
    4. Set a security manager by passing the following options to the JVM:
      -Djava.security.manager -Djava.security.policy="<jboss home>\server\default\conf\server.policy"
import java.rmi.RemoteException;
import java.util.Properties;

import javax.ejb.CreateException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

import com.teradata.tap.system.query.ejb.QueryEngineRemote;
import com.teradata.tap.system.query.ejb.QueryEngineRemoteHome;

/**
 * Call a business method of an EJB running on JBoss
 */
public class ExternalCallEjbSample {

        public static void main(String[] args) {
                // 1: Get the naming Context
                // Required JARs (in jboss/server/default/lib): jboss-common.jar, jnpserver.jar 
                Properties props = new Properties();
                //      Matches the java.naming.factory.initial property in jndi.properties
                props.put(Context.INITIAL_CONTEXT_FACTORY,
                                "org.jnp.interfaces.NamingContextFactory");
                //      Matches the java.naming.provider.url property in jndi.properties
                props.put(Context.PROVIDER_URL, "jnp://localhost:1099");
                props.put(Context.URL_PKG_PREFIXES,
                                "org.jboss.naming:org.jnp.interfaces");
                QueryEngineRemoteHome queryEngineHome = null;

                try {

                        Context ctx = new InitialContext(props);

                        /*/ Print all entries in the JNDI
                         NamingEnumeration ne = ctx.list("java:");
                         while (ne.hasMore()) {
                         System.out.println("A: " + ne.next().toString());
                         } //*/

                        // Look up and instantiate the home interface of the EJB
                        // IMPORTANT: It fails if no SecurityManager specified for RMI class loader will be disabled
                        // -> add these options to the JVM:
                        // -Djava.security.manager -Djava.security.policy=" home>\server\default\conf\server.policy"
                        String beanName = QueryEngineRemoteHome.JNDI_NAME;
                        System.out.println("Looking up '" + beanName + "'");
                        Object lookup = ctx.lookup(beanName);

                        queryEngineHome = (QueryEngineRemoteHome) PortableRemoteObject
                                        .narrow(lookup, QueryEngineRemoteHome.class);

                } catch (NamingException e) {
                        System.out.println("new InitialContext failed:" + e);
                }

                // 2. Instantiate the (remote) EJB and call its business method(s)
                // 2.1 I have to authenticate unless security allows anybody to call create on the EJB
                //      Otherwise an EJBException: checkSecurityAssociation will be thrown.
                // TODO: JVM option -Djava.security.auth.login.config==sample_jaas.config - use org.jboss.security.ClientLoginModule
                // and have  home>\server\default\lib\jbosssx.jar on the path (class ClientLoginModule)
                // Listing of sample_jaas.config:
                //      jboss_jaas { org.jboss.security.ClientLoginModule required debug=true; };
                LoginContext loginContext = null;
                boolean loggedIn = false;
                try {
                        CallbackHandler handler = new MyPresetCallbackHandler("tapdev","tapdev");
                        // jboss_jaas - name of a configuration in the jaas config file 
                        loginContext = new LoginContext("jboss_jaas", handler);
                        System.out.println("Created LoginContext");
                        loginContext.login(); // throws LoginException
                        System.out.println("Logged in.");
                        loggedIn = true;
                } catch (LoginException le) {
                        System.out.println("Login failed");
                        le.printStackTrace();
                }

                // Create & use the EJB:
                if (loggedIn && queryEngineHome != null) {
                        try {
                                QueryEngineRemote queryEngine = queryEngineHome.create();
                                System.out.println("queryEngine remote created.");
                                // TODO: call business method(s)
                        } catch (RemoteException e1) {
                                e1.printStackTrace();
                        } catch (CreateException e1) {
                                e1.printStackTrace();
                        }
                }

                // Log out
                if (loggedIn && loginContext != null) {
                        try {
                                loginContext.logout();
                        } catch (LoginException e) {
                                System.out.println("Logout failed:" + e);
                        }
                }

                System.out.println("## DONE! ##");
        } // main

        /** Authentication CallbackHandler with preset username/password. */
        static class MyPresetCallbackHandler implements CallbackHandler {
                String username;

                char[] password;

                public MyPresetCallbackHandler(String username, String password) {
                        this.username = username;
                        this.password = password.toCharArray();
                }

                public void handle(Callback[] callbacks) throws java.io.IOException,
                                UnsupportedCallbackException {
                        for (int i = 0; i < callbacks.length; i++) {
                                Callback callback = callbacks[i];
                                if (callback instanceof NameCallback) {
                                        ((NameCallback) callback).setName(username);
                                } else if (callback instanceof PasswordCallback) {
                                        ((PasswordCallback) callback).setPassword(password);
                                } else {
                                        throw new UnsupportedCallbackException(callback,
                                                        "Unrecognized Callback");
                                }
                        }
                }// handle 
        }// MyPresetCallbackHandler
}

See EjbLocator.java
and EjbLocatorException.java.
With them, you can replace all above with QueryEngineRemote queryEngine = (QueryEngineRemote) EjbLocator.getInstance().locate( QueryEngineRemoteHome.JNDI_NAME );

Posted in j2ee | Tagged: , , , | Comments Off