Eclipse RCP Standalone Client with Glassfish v3
This code fragment shows how an Eclipse RCP application can connect to Glassfish v3 as a stand-alone client (including full security). It consists of the following parts:
- Eclipse plugin containing project-specific server classes, such remote interfaces for session beans and entity beans. It also contains all the necessary GFv3 Jars for the client app to run on a remote JVM. We call this : com.ansis.timetracker.client.lib.gf.
- Eclipse client plugin(s). These plugins contain all the client-specific code and UI functionality. Each such plugin (here we provide one sample plugin) all depend on com.ansis.timetracker.client.lib.gf. It's name in our example is com.ansis.timetracker.client.
Fragment 1: MANIFEST.MF of com.ansis.timetracker.client.lib.gf
The Bundle-ClassPath section contains two project specific Jars (aef-util.jar, timetracker.jar), which contain all necessary server classes (remote interfaces, etc.). All other Jars are identical to the Classpath section in the gf-client-module.jar found in the Glassfish/modules directory.
===========================================
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: iREMS Server Plug-in
Bundle-SymbolicName: com.ansis.timetracker.client.lib.gf
Bundle-Version: 2.0.0.b1
Bundle-Vendor: ANSIS
Bundle-Localization: plugin
Bundle-ClassPath: lib/aef-util.jar,
lib/timetracker.jar,
srv_3_0_1/hk2-core.jar,
srv_3_0_1/hk2.jar,
srv_3_0_1/config.jar,
srv_3_0_1/auto-depends.jar,
srv_3_0_1/tiger-types-osgi.jar,
srv_3_0_1/bean-validator.jar,
srv_3_0_1/common-util.jar,
srv_3_0_1/glassfish-api.jar,
srv_3_0_1/config-types.jar,
srv_3_0_1/grizzly-utils.jar,
srv_3_0_1/management-api.jar,
srv_3_0_1/javax.servlet.jar,
srv_3_0_1/security.jar,
srv_3_0_1/config-api.jar,
srv_3_0_1/grizzly-config.jar,
srv_3_0_1/grizzly-http.jar,
srv_3_0_1/grizzly-framework.jar,
srv_3_0_1/grizzly-rcm.jar,
srv_3_0_1/grizzly-portunif.jar,
srv_3_0_1/osgi-adapter.jar,
srv_3_0_1/dol.jar,
srv_3_0_1/endorsed/javax.annotation.jar,
srv_3_0_1/javax.transaction.jar,
srv_3_0_1/javax.enterprise.deploy.jar,
srv_3_0_1/javax.persistence.jar,
srv_3_0_1/javax.resource.jar,
srv_3_0_1/javax.ejb.jar,
srv_3_0_1/deployment-common.jar,
srv_3_0_1/internal-api.jar,
srv_3_0_1/asm-all-repackaged.jar,
srv_3_0_1/annotation-framework.jar,
srv_3_0_1/javax.security.auth.message.jar,
srv_3_0_1/javax.security.jacc.jar,
srv_3_0_1/ejb-internal-api.jar,
srv_3_0_1/connectors-internal-api.jar,
srv_3_0_1/transaction-internal-api.jar,
srv_3_0_1/ldapbp-repackaged.jar,
srv_3_0_1/gmbal.jar,
srv_3_0_1/ejb-container.jar,
srv_3_0_1/kernel.jar,
srv_3_0_1/pkg-client.jar,
srv_3_0_1/flashlight-framework.jar,
srv_3_0_1/flashlight-agent.jar,
srv_3_0_1/monitoring-core.jar,
srv_3_0_1/stats77.jar,
srv_3_0_1/deployment-javaee-core.jar,
srv_3_0_1/container-common.jar,
srv_3_0_1/glassfish-naming.jar,
srv_3_0_1/admin-util.jar,
srv_3_0_1/mail.jar,
srv_3_0_1/activation.jar,
srv_3_0_1/grizzly-comet.jar,
srv_3_0_1/persistence-common.jar,
srv_3_0_1/orb-connector.jar,
srv_3_0_1/glassfish-corba-orbgeneric.jar,
srv_3_0_1/glassfish-corba-omgapi.jar,
srv_3_0_1/appclient.security.jar,
srv_3_0_1/ejb.security.jar,
srv_3_0_1/glassfish-corba-csiv2-idl.jar,
srv_3_0_1/glassfish-corba-orb.jar,
srv_3_0_1/glassfish-corba-newtimer.jar,
srv_3_0_1/glassfish-corba-codegen.jar,
srv_3_0_1/glassfish-corba-asm.jar,
srv_3_0_1/orb-iiop.jar,
srv_3_0_1/acc-config.jar,
srv_3_0_1/webservices.security.jar,
srv_3_0_1/web-glue.jar,
srv_3_0_1/web-cli.jar,
srv_3_0_1/cli-framework.jar,
srv_3_0_1/amx-j2ee.jar,
srv_3_0_1/amx-core.jar,
srv_3_0_1/javax.management.j2ee.jar,
srv_3_0_1/war-util.jar,
srv_3_0_1/javax.servlet.jsp.jar,
srv_3_0_1/web-naming.jar,
srv_3_0_1/glassfish-ee-api.jar,
srv_3_0_1/web-core.jar,
srv_3_0_1/jsp-impl.jar,
srv_3_0_1/el-impl.jar,
srv_3_0_1/admin-core.jar,
srv_3_0_1/web-gui-plugin-common.jar,
srv_3_0_1/websecurity.jar,
srv_3_0_1/webservices-osgi.jar,
srv_3_0_1/jaxb-osgi.jar,
srv_3_0_1/endorsed/jaxb-api-osgi.jar,
srv_3_0_1/endorsed/webservices-api-osgi.jar,
srv_3_0_1/woodstox-osgi.jar,
srv_3_0_1/mimepull.jar,
srv_3_0_1/jsr109-impl.jar,
srv_3_0_1/grizzly-http-servlet.jar,
srv_3_0_1/work-management.jar,
srv_3_0_1/connectors-inbound-runtime.jar,
srv_3_0_1/connectors-runtime.jar,
srv_3_0_1/glassfish.jar,
srv_3_0_1/jts.jar,
srv_3_0_1/jta.jar,
srv_3_0_1/jms-core.jar,
srv_3_0_1/javax.jms.jar,
srv_3_0_1/org.eclipse.persistence.core.jar,
srv_3_0_1/org.eclipse.persistence.asm.jar,
srv_3_0_1/org.eclipse.persistence.antlr.jar,
srv_3_0_1/org.eclipse.persistence.jpa.jar,
srv_3_0_1/org.eclipse.persistence.jpa.modelgen.jar,
srv_3_0_1/org.eclipse.persistence.oracle.jar,
srv_3_0_1/jpa-connector.jar,
srv_3_0_1/cmp-internal-api.jar
Require-Bundle: org.eclipse.core.runtime;bundle-version="3.4.0"
Bundle-ActivationPolicy: lazy
Export-Package: com.ansis.aef.util,
com.ansis.aef.util.audit.exception,
com.ansis.aef.util.audit.feedback,
com.ansis.aef.util.audit.logger,
com.ansis.aef.util.audit.profiling,
com.ansis.aef.util.io,
com.ansis.aef.util.io.csv,
com.ansis.aef.util.io.excel,
com.ansis.aef.util.io.html,
com.ansis.aef.util.io.stream,
com.ansis.aef.util.manipulation,
com.ansis.aef.util.manipulation.collection,
com.ansis.aef.util.manipulation.number2words,
com.ansis.aef.util.manipulation.security,
com.ansis.aef.util.pattern.customsortable,
com.ansis.aef.util.pattern.sortedtree,
com.ansis.aef.util.pattern.treeitem,
com.ansis.aef.util.ui.presentation,
com.ansis.timetracker.client.lib.gf,
com.ansis.timetracker.server,
com.ansis.timetracker.server.exception,
com.ansis.timetracker.server.model.helper,
com.ansis.timetracker.server.model.person,
com.ansis.timetracker.server.model.project,
com.ansis.timetracker.server.session.remote,
com.ansis.timetracker.server.util,
com.sun.appserv.security,
javax.ejb
As you can see, it lists all necessary GFv3 Jars, but only exports two necessary packages.
Fragment 2: Lookup Code in com.ansis.timetracker.client.lib.gf
The class called ConnectionDetails does all the work of looking up a requested session bean stub.
======== Listing ConnectionDetails.java ============
package com.ansis.timetracker.server.util;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
import com.ansis.aef.util.audit.logger.AEFLog;
import com.ansis.aef.util.audit.logger.AEFLogger;
import com.ansis.aef.util.manipulation.StringUtils;
import com.ansis.timetracker.server.exception.TTRuntimeException;
import com.ansis.timetracker.server.session.remote.ActivityTrackerBeanRemote;
import com.ansis.timetracker.server.session.remote.DashboardFacadeBeanRemote;
import com.sun.appserv.security.ProgrammaticLogin;
/**
* Contains all the details necessary to connect to the iREMS server.
*
* EJB FAQ: https://glassfish.dev.java.net/javaee5/ejb/EJB_FAQ.html
*
* GF CORBA home page: https://glassfish-corba.dev.java.net/
*
* RMI JVM settings: java.sun.com/j2se/1.4.2/docs/guide/rmi/sunrmiproperties.html
*
* Performance tuning RMI/J2EE: www.javaperformancetuning.com/tips/j2ee_rmi.shtml
*
*
* Connecting standalone client to GFv3:
* https://glassfish.dev.java.net/javaee5/ejb/EJB_FAQ.html#StandaloneRemoteEJB
* forums1.java.net/jive/message.jspa
* forums.java.net/jive/message.jspa
*
* @author akozma
* Copyright ANSIS, 2010: please reference ANSIS when reusing.
*/
@SuppressWarnings("nls")
public class ConnectionDetails implements Serializable {
// ==================== 1. Static Fields ========================
private static final long serialVersionUID = -4710045391762303501L;
private static AEFLog log = AEFLogger.getLogger(ConnectionDetails.class);
private static final String PORT_SEPARATOR = ":";
private static final String DEFAULT_HOST = "localhost";
private static final String PROD_PORT_ALIASES = "p, prod, production";
private static final String SANDBOX_PORT_ALIASES = "s, , sb, test, sandb, sandbox";
// ====================== 2. Instance Fields =============================
private String user;
private String password;
private String server;
private String customPort;
private InitialContext context;
/**
* Remote server bean object.
*/
private ActivityTrackerBeanRemote activityTrackerBean = null;
private DashboardFacadeBeanRemote dashboardFacade = null;
// ==================== 4. Constructors ====================
/**
* Server is localhost with default port.
*/
public ConnectionDetails(final String user, final String password) {
this(user, password, "localhost");
}
/**
* Creates the initial context and sets the Security Context.
* Please note that if a host address without is port is supplied, then the appropriate port
* number is appended automatically.
*
* @param user
* @param server
* @param port TODO
* @param MD5 encoded password
*/
public ConnectionDetails(final String user, final String password, final String server) {
setUser(user);
setPassword(password);
setServer(server);
}
// ==================== 7. Getters & Setters ====================
public String getUser() {
return user;
}
public void setUser(final String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(final String password) {
this.password = password;
}
public String getServer() {
return server;
}
public void setServer(final String server) {
this.server = server;
}
// ==================== 8. Business Methods ====================
@SuppressWarnings("unchecked")
public <T> T lookup(final Class<T> remoteInterface, final String jndiName) {
try {
return (T) getInitialContext().lookup(jndiName);
} catch (final NamingException e) {
throw new TTRuntimeException("Error looking up remote interface for: " + jndiName, e);
}
}
/**
* Creates an initial context to login to the server.
*/
public Context getInitialContext() {
if (context != null)
return context;
// --------------------- <Set JAAS Config, so we don't have to read from config file> -----------------------
Configuration.setConfiguration(new Configuration() {
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(final String name) {
final Map<String,Boolean> options = new HashMap<String, Boolean>();
options.put("debug", new Boolean(false));
if ("default".equals(name))
return new AppConfigurationEntry[] {new AppConfigurationEntry("com.sun.enterprise.security.auth.login.ClientPasswordLoginModule", LoginModuleControlFlag.REQUIRED, options)};
if ("certificate".equals(name))
return new AppConfigurationEntry[] {new AppConfigurationEntry("com.sun.enterprise.security.auth.login.ClientCertificateLoginModule", LoginModuleControlFlag.REQUIRED, options)};
throw new TTRuntimeException("New Configuration was asked for: " + name + ", but it should have been default or certificate!");
}
@Override
public void refresh() {
// we don't need to refresh anything!
}
});
final ProgrammaticLogin pm = new ProgrammaticLogin();
final boolean success = pm.login(getUser(), getPassword());
if (!success)
log.warn("Setup of login unsuccessful!");
try {
context = new InitialContext(createPropertiesExisting());
} catch (final NamingException e) {
throw new TTRuntimeException("Error while logging in", e);
}
return context;
}
/**
* That's the default initial naming factory that works with Dynamic RMI/IIOP stub generation.
*
* @return
*/
private Properties createPropertiesExisting() {
final Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
// Only needed if server is running on a different host than localhost:
if (!StringUtils.isEmpty(getServer()))
props.setProperty("org.omg.CORBA.ORBInitialHost", getServer());
// Optional. Defaults to 3700. Only needed if target orb port is not 3700.
if (!StringUtils.isEmpty(getPortNumber()))
props.setProperty("org.omg.CORBA.ORBInitialPort", getPortNumber());
// props.setProperty("com.sun.appserv.iiop.orbconnections","5");
//
// //Increase ORB Response Timeout to 2 hours instead of 30 min:
// props.setProperty("com.sun.corba.ee.transport.ORBTCPTimeouts", "500:90000:20");
// props.setProperty("com.sun.corba.ee.transport.ORBWaitForResponseTimeout", "7200000");
return props;
}
public ActivityTrackerBeanRemote getActivityTrackerBean() {
if (activityTrackerBean == null) {
activityTrackerBean = lookup(ActivityTrackerBeanRemote.class, ActivityTrackerBeanRemote.JNDIName);
}
return activityTrackerBean;
}
/**
* @return the bean object on the remote server.
*/
public DashboardFacadeBeanRemote getDashboardFacadeBean() {
if (dashboardFacade == null) {
dashboardFacade = lookup(DashboardFacadeBeanRemote.class, DashboardFacadeBeanRemote.JNDIName);
}
return dashboardFacade;
}
public void resetBeans() {
activityTrackerBean = null;
dashboardFacade = null;
}
// ==================== 12. Presentation ====================
private String getPortNumber() {
return "30037";
}
@Override
public String toString() {
return "";
}
Fragment 3: MANIFEST.MF of Client Code Plugin
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Time Tracker
Bundle-SymbolicName: com.ansis.timetracker.client; singleton:=true
Bundle-Version: 2.0.0
Bundle-Activator: com.ansis.timetracker.client.ClientActivator
Bundle-Vendor: ANSIS
Bundle-Localization: plugin
Require-Bundle: org.eclipse.ui;visibility:=reexport,
org.eclipse.core.runtime;visibility:=reexport,
org.eclipse.ui.forms;visibility:=reexport,
org.eclipse.jface.text,
org.eclipse.core.resources,
org.eclipse.ui.editors,
org.eclipse.ui.ide,
com.ansis.timetracker.client.lib.gf;visibility:=reexport
Eclipse-LazyStart: true
Bundle-ClassPath: .,
lib/nebula_cdatetime_0.9.0.jar
Export-Package: com.ansis.timetracker.client,
com.ansis.timetracker.client.core,
com.ansis.timetracker.client.dialogs,
com.ansis.timetracker.client.views,
com.ansis.timetracker.client.views.components,
com.ansis.timetracker.client.wizards,
org.eclipse.swt.nebula.widgets.cdatet
Fragment 4: Code in Client Plugin using Session Bean Stubs
This code simply uses the SessionBean Remote Interface and calls its methods:
DashboardFacadeBeanRemote dashboard = getConnection().getDashboardFacadeBean();
dashboard.run

