/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.appclient;
import com.sun.appserv.naming.S1ASCtxFactory;
import com.sun.enterprise.appclient.AppContainer;
import com.sun.enterprise.appclient.HttpAuthenticator;
import com.sun.enterprise.appclient.jws.TemplateCache;
import com.sun.enterprise.appclient.jws.Util;
import com.sun.enterprise.config.clientbeans.CertDb;
import com.sun.enterprise.config.clientbeans.ClientBeansFactory;
import com.sun.enterprise.config.clientbeans.ClientContainer;
import com.sun.enterprise.config.clientbeans.ClientCredential;
import com.sun.enterprise.config.clientbeans.ElementProperty;
import com.sun.enterprise.config.clientbeans.Security;
import com.sun.enterprise.config.clientbeans.Ssl;
import com.sun.enterprise.config.clientbeans.TargetServer;
import com.sun.enterprise.config.ConfigContext;
import com.sun.enterprise.config.ConfigException;
import com.sun.enterprise.config.ConfigFactory;
import com.sun.enterprise.connectors.ActiveResourceAdapter;
import com.sun.enterprise.connectors.ConnectorRegistry;
import com.sun.enterprise.connectors.ConnectorRuntime;
import com.sun.enterprise.deployment.*;
import com.sun.enterprise.deployment.archivist.AppClientArchivist;
import com.sun.enterprise.deployment.archivist.ApplicationArchivist;
import com.sun.enterprise.deployment.backend.ClientJarMakerThread;
import com.sun.enterprise.deployment.deploy.shared.AbstractArchive;
import com.sun.enterprise.deployment.deploy.shared.FileArchive;
import com.sun.enterprise.deployment.deploy.shared.InputJarArchive;
import com.sun.enterprise.deployment.interfaces.SecurityRoleMapperFactory;
import com.sun.enterprise.deployment.interfaces.SecurityRoleMapperFactoryMgr;
import com.sun.enterprise.InjectionManager;
import com.sun.enterprise.J2EESecurityManager;
import com.sun.enterprise.naming.ProviderManager;
import com.sun.enterprise.security.GUIErrorDialog;
import com.sun.enterprise.security.SSLUtils;
import com.sun.enterprise.server.logging.ACCLogManager;
import com.sun.enterprise.Switch;
import com.sun.enterprise.util.FileUtil;
import com.sun.enterprise.util.i18n.StringManager;
import com.sun.enterprise.util.JarClassLoader;
import com.sun.enterprise.util.ORBManager;
import com.sun.enterprise.util.shared.ArchivistUtils;
import com.sun.enterprise.util.Utility;
import com.sun.logging.LogDomains;
import com.sun.web.server.HttpsURLStreamHandlerFactory;
import java.io.*;
import java.net.*;
import java.util.Iterator;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.LogManager;
import java.util.Properties;
import java.util.Vector;
import javax.security.auth.message.config.AuthConfigFactory;
import com.sun.enterprise.security.jmac.config.GFAuthConfigFactory;
import com.sun.enterprise.security.UsernamePasswordStore;
/**
* This is the main that gets invoked first. It initializes the application
* client container for an application client component
* and other related items and then invokes the real main written by the
* application developer.
*/
public class Main
{
private static final String CLIENT = "-client";
private static final String NAME = "-name";
private static final String MAIN_CLASS = "-mainclass";
private static final String TEXT_AUTH = "-textauth";
private static final String XML_PATH = "-xml";
private static final String ACC_CONFIG_XML = "-configxml";
private static final String DEFAULT_CLIENT_CONTAINER_XML = "sun-acc.xml";
// duplicated in com.sun.enterprise.jauth.ConfigXMLParser
private static final String SUNACC_XML_URL = "sun-acc.xml.url";
private static final String NO_APP_INVOKE = "-noappinvoke";
//Added for allow user to pass user name and password through command line.
private static final String USER = "-user";
private static final String PASSWORD = "-password";
private static final String PASSWORD_FILE = "-passwordfile";
private static final String LOGIN_NAME = "j2eelogin.name";
private static final String LOGIN_PASSWORD = "j2eelogin.password";
private static final String DASH = "-";
private static final String lineSep = System.getProperty("line.separator");
/**
* Property names used on the server to send these values to a Java Web Start client
* and by the ACC when running under Java Web Start to retrieve them
*/
public static final String APPCLIENT_IIOP_DEFAULTHOST_PROPERTYNAME = "com.sun.aas.jws.iiop.defaultHost";
public static final String APPCLIENT_IIOP_DEFAULTPORT_PROPERTYNAME = "com.sun.aas.jws.iiop.defaultPort";
public static final String APPCLIENT_IIOP_FAILOVER_ENDPOINTS_PROPERTYNAME = "com.sun.aas.jws.iiop.failover.endpoints";
public static final String APPCLIENT_PROBE_CLASSNAME_PROPERTYNAME = "com.sun.aas.jws.probeClassName";
/** Prop name for keeping temporary files */
public static final String APPCLIENT_RETAIN_TEMP_FILES_PROPERTYNAME = "com.sun.aas.jws.retainTempFiles";
/** property name used to indicate that Java Web Start is active */
public static final String APPCLIENT_ISJWS_PROPERTYNAME = "com.sun.aas.jws.isJWS";
/** Prop used when running under Java Web Start to point to a temporarily-created default file.
*This property appears in the template for the default sun-acc.xml content. Logic below
*assigns a value to it and then uses it to substitute in the template to create the
*actual content. (This is not a property set in the environment and then retrieved by Main.)
*/
public static final String SUN_ACC_SECURITY_CONFIG_PROPERTY = "security.config.file";
/** Used for constructing the name of the temp file that will hold the login conf. content */
private static final String LOGIN_CONF_FILE_PREFIX = "login";
private static final String LOGIN_CONF_FILE_SUFFIX = ".conf";
/** The system property to be set that is later read by jaas */
private static final String LOGIN_CONF_PROPERTY_NAME = "java.security.auth.login.config";
/** Names of templates for default config for Java Web Start */
private static final String DEFAULT_TEMPLATE_PREFIX = "jws/templates/";
private static final String SUN_ACC_DEFAULT_TEMPLATE = DEFAULT_TEMPLATE_PREFIX + "default-sun-accTemplate.xml";
private static final String WSS_CLIENT_CONFIG_TEMPLATE = DEFAULT_TEMPLATE_PREFIX + "default-wss-client-configTemplate.xml";
private static final String LOGIN_CONF_TEMPLATE = DEFAULT_TEMPLATE_PREFIX + "appclientlogin.conf";
/** Naming for temporary files created under Java Web Start */
private static final String WSS_CLIENT_CONFIG_PREFIX = "wsscc";
private static final String WSS_CLIENT_CONFIG_SUFFIX = ".xml";
private static final String SUN_ACC_PREFIX = "sunacc";
private static final String SUN_ACC_SUFFIX = ".xml";
private static Logger _logger;
private static final boolean debug = false;
private static StringManager localStrings =
StringManager.getManager(Main.class);
private static boolean guiAuth;
private static boolean runClient=true;
private static String host;
private static String port;
/** accumulates info to be logged before the logger is initialized */
private static StringBuilder pendingLogInfo = new StringBuilder();
private static StringBuilder pendingLogFine = new StringBuilder();
/** Saved arguments so they are accessible from the AWT thread if needed */
private static String [] args;
/** Records whether ACC is currently running under Java Web Start */
private static boolean isJWS;
/** Records whether temp config files created while running under Java Web Start should be retained */
private static boolean retainTempFiles = false;
private static final String SUPPORT_MODULE_FORMAT = "support.module.format";
private static final String SUPPORT_MODULE_FORMAT_DEFAULT_VALUE = "true";
private static final String supportModuleFormatValue = System.getProperty(SUPPORT_MODULE_FORMAT, SUPPORT_MODULE_FORMAT_DEFAULT_VALUE);
private static final boolean supportModuleFormat = Boolean.parseBoolean(supportModuleFormatValue);
private static boolean lb_enabled = false;
public static void main(String[] args) {
if (supportModuleFormat) {
new MainWithModuleSupport(args);
} else {
new Main(args);
}
}
public Main(String[] args) {
String arg = null;
String clientJar = null;
String displayName = null;
String mainClass = null;
String xmlPath = null;
String accConfigXml = null;
String jwsACCConfigXml = null;
Vector<String> appArgs = new Vector<String>();
int i = 0;
isJWS = Boolean.getBoolean(APPCLIENT_ISJWS_PROPERTYNAME);
retainTempFiles = Boolean.getBoolean(APPCLIENT_RETAIN_TEMP_FILES_PROPERTYNAME);
guiAuth = Boolean.valueOf
(System.getProperty("auth.gui", "true")).booleanValue();
// Parse command line arguments.
if(args.length < 1) {
usage();
} else {
while(i < args.length) {
arg = args[i++];
if(arg.equals(CLIENT)) {
if(i < args.length && !args[i].startsWith(DASH)) {
clientJar = args[i++];
} else {
usage();
}
} else if(arg.equals(NAME) && !args[i].startsWith(DASH)) {
//only one option can be used [-mainclass|-name]
if(i < args.length && mainClass == null) {
displayName = args[i++];
} else {
usage();
}
} else if(arg.equals(MAIN_CLASS) && !args[i].startsWith(DASH)) {
//only one option can be used [-mainclass|-name]
if(i < args.length && displayName == null) {
mainClass = args[i++];
} else {
usage();
}
} else if(arg.equals(XML_PATH) ) {
if(i < args.length && xmlPath == null) {
xmlPath = args[i++];
} else {
usage();
}
} else if(arg.equals(ACC_CONFIG_XML) ) {
if(i < args.length && accConfigXml == null) {
accConfigXml = args[i++];
} else {
usage();
}
} else if(arg.equals(TEXT_AUTH)) {
// Overrides legacy auth.gui setting.
guiAuth = false;
} else if(arg.equals(NO_APP_INVOKE)) {
runClient = false;
} else if(arg.equals(USER)) {
if(i < args.length) {
System.setProperty(LOGIN_NAME, args[i++]);
} else {
usage();
}
} else if(arg.equals(PASSWORD)) {
if (i < args.length) {
System.setProperty(LOGIN_PASSWORD, args[i++]);
} else {
usage();
}
} else if (arg.equals(PASSWORD_FILE)) {
if (i < args.length) {
try {
System.setProperty(LOGIN_PASSWORD,
loadPasswordFromFile(args[i++]));
} catch(IOException ex) {
throw new IllegalArgumentException(ex.getMessage());
}
} else {
usage();
}
} else {
appArgs.add(arg);
}
}
}
String uname = System.getProperty(LOGIN_NAME);
String upass = System.getProperty(LOGIN_PASSWORD);
if( uname != null || upass != null ) {
UsernamePasswordStore.set(uname, upass);
}
String className=null;
if(clientJar == null && ! isJWS) {
// maybe the user has specified the appclient class as the first
// parameter using the local directory as the classpath.
if (appArgs.size()==0 && mainClass==null) {
usage();
}
// ok, if the first parameter may be the appclient class, let's check
// for its existence.
String value;
if (mainClass==null) {
value = appArgs.elementAt(0);
} else {
value = mainClass;
}
if (value.endsWith(".class")) {
className = value.substring(0, value.length()-".class".length());
} else {
className = value;
}
String path = className.replace('.', File.separatorChar) + ".class";
File file = new File(path);
if (!file.isAbsolute()) {
file = new File(System.getProperty("user.dir"), path);
}
/*
*If the user omitted the client jar from the command line and
*we cannot find the first argument as a class in the user's
*home directory and this is not a JWS launch, then the user has
*not entered a valid command.
*/
if (!file.exists() && ! isJWS) {
// no clue what the user is trying to do
usage();
}
}
/* validate xmlPath */
if (xmlPath != null) {
validateXMLFile(xmlPath);
} else if (accConfigXml != null ) {
validateXMLFile(accConfigXml);
xmlPath = accConfigXml; //use AS_ACC_CONFIG
} else if (isJWS) {
/*
*Neither -xml nor -configxml were present and this is a Java
*Web Start invocation. Use
*the alternate mechanism to create the default config.
*/
try {
jwsACCConfigXml = prepareJWSConfig();
if (jwsACCConfigXml != null) {
validateXMLFile(jwsACCConfigXml);
xmlPath = jwsACCConfigXml;
}
} catch (Throwable thr) {
System.err.println("Error preparing configuration");
thr.printStackTrace(System.err);
System.exit(1);
}
}
// make sure the default logger for ACCLogManager is set
_logger = LogDomains.getLogger(LogDomains.ACC_LOGGER);
LogManager logMgr = LogManager.getLogManager();
if (logMgr instanceof ACCLogManager) {
((ACCLogManager) logMgr).init(xmlPath);
}
/*
*Flush any pending log output.
*/
if (pendingLogInfo.length() > 0) {
_logger.info(pendingLogInfo.toString());
if (pendingLogFine.length() > 0) {
_logger.fine(pendingLogFine.toString());
}
}
/*
*If this is a Java Web Start invocation, prepare the user-specified
*or default login configuration.
*/
if (isJWS) {
try {
prepareJWSLoginConfig();
} catch (Throwable thr) {
_logger.log(Level.SEVERE, "Error preparing default login configuration", thr);
System.exit(1);
}
}
Utility.checkJVMVersion();
/* security init */
SecurityManager secMgr = System.getSecurityManager();
if (secMgr != null &&
!(J2EESecurityManager.class.equals(secMgr.getClass()))) {
J2EESecurityManager mgr = new J2EESecurityManager();
System.setSecurityManager(mgr);
}
if (_logger.isLoggable(Level.INFO)) {
if (secMgr != null) {
_logger.info("acc.secmgron");
} else {
_logger.info("acc.secmgroff");
}
}
try{
/* setup keystores.
* This is required, for appclients that want to use SSL, especially
* HttpsURLConnection to perform Https.
*/
SSLUtils.initStoresAtStartup();
} catch (Exception e){
/* This is not necessarily an error. This will arise
* if the user has not specified keystore/truststore properties.
* and does not want to use SSL.
*/
if(_logger.isLoggable(Level.FINER)){
// show the exact stack trace
_logger.log(Level.FINER, "main.ssl_keystore_init_failed", e);
} else{
// just log it as a warning.
_logger.log(Level.WARNING, "main.ssl_keystore_init_failed");
}
}
try {
/* setup jsr 196 factory
* define default factory if it is not already defined
*/
String defaultFactory = java.security.Security.getProperty
(AuthConfigFactory.DEFAULT_FACTORY_SECURITY_PROPERTY);
if (defaultFactory == null) {
java.security.Security.setProperty
(AuthConfigFactory.DEFAULT_FACTORY_SECURITY_PROPERTY,
GFAuthConfigFactory.class.getName());
}
} catch (Exception e) {
// XXX put string in catablog
_logger.log(Level.WARNING, "main.jmac_default_factory");
}
try {
Switch.getSwitch().setProviderManager(ProviderManager.getProviderManager());
// added for ClientContainer.xml initialization
setTargetServerProperties(xmlPath);
int exitCode = 0; // 0 for success
AppContainer container = null;
// Ensure cleanup is performed, even if
// application client calls System.exit().
Cleanup cleanup = new Cleanup();
Runtime runtime = Runtime.getRuntime();
runtime.addShutdownHook(cleanup);
// Set the HTTPS URL stream handler.
java.security.AccessController.doPrivileged(new
java.security.PrivilegedAction() {
public Object run() {
URL.setURLStreamHandlerFactory(new
HttpsURLStreamHandlerFactory());
return null;
}
});
File appClientFile;
/*
*For Java Web Start launches, locate the jar file implicitly.
*Otherwise, if the user omitted the clientjar argument (and the
*code has gotten this far) then the user must have used the
*first argument as the name of the class in ${user.dir} to run. If
*the user actually specified the clientjar argument, then use that
*value as the file spec for the client jar.
*/
if (isJWS) {
/*
*Java Web Start case.
*/
appClientFile = findAppClientFileForJWSLaunch();
} else if (clientJar==null) {
/*
*First-argument-as-class-name case
*/
File userDir = new File(System.getProperty("user.dir"));
File appClientClass = new File(userDir, className);
appClientFile = appClientClass.getParentFile();
} else {
/*
*Normal case - clientjar argument specified.
*/
appClientFile = new File(clientJar);
}
// class loader
URL[] urls = new URL[1];
urls[0] = appClientFile.toURI().toURL();
/*
*Set the parent of the new class loader to the current loader.
*The Java Web Start-managed class path is implemented in the
*current loader, so it must remain on the loader stack.
*/
ClassLoader currentCL = Thread.currentThread().getContextClassLoader();
ClassLoader jcl = new URLClassLoader(urls, currentCL);
Thread.currentThread().setContextClassLoader(jcl);
ApplicationClientDescriptor appDesc = null;
// create the application container and call preInvoke.
/*
*Note that if the client jar argument is missing it can mean one of
*two things: Either the user used the first argument to specify
*the class to execute or
*this is a Java Web Start launch.
*/
if((clientJar!=null || isJWS ) && FileUtil.isEARFile(appClientFile)) {
// loads application with only the clients
Application app = null;
try {
ApplicationArchivist arch = new ApplicationArchivist();
arch.setAnnotationProcessingRequested(true);
// Set class loader here before opening archive
// to enable validation.
arch.setClassLoader(jcl);
app = (Application) arch.open(appClientFile);
} catch (Throwable t) {
_logger.log(Level.WARNING, "acc.failed_load_client_desc",
clientJar);
throw t;
}
app.setClassLoader(jcl);
appDesc = null;
int appclientCount = 0;
for (Iterator itr =
app.getApplicationClientDescriptors().iterator();
itr.hasNext();) {
ApplicationClientDescriptor next =
(ApplicationClientDescriptor) itr.next();
appclientCount++;
}
for (Iterator itr =
app.getApplicationClientDescriptors().iterator();
itr.hasNext();) {
ApplicationClientDescriptor next =
(ApplicationClientDescriptor) itr.next();
if (appclientCount == 1) {
//for -mainclass <class name> option
if (mainClass != null) {
if (!next.getMainClassName().equals(mainClass)) {
next.setMainClassName(mainClass);
}
}
appDesc = next;
break;
} else {//app contains multiple app client jars
if (mainClass != null) {
if (next.getMainClassName().equals(mainClass)) {
appDesc = next;
break;
}
} else {
if (displayName == null) {
_logger.log(Level.SEVERE,"acc.no_mainclass_or_displayname");
System.exit(1);
} else if (displayName != null && next.getName().equals(displayName)) {
if(appDesc == null) {
appDesc = next;
} else {
//multiple app duplicated display name
_logger.log(Level.WARNING, "acc.duplicate_display_name");
System.exit(1);
}
}
}
}
}
//construct AppContainer using appDesc
if (appDesc != null) {
container = new AppContainer(appDesc, guiAuth);
// the archive uri must have absolute path
//f = new File (f, appDesc.getModuleDescriptor().getArchiveUri());
}
} else {
// we are dealing with a class file or a client jar
// reads std & iAS application xml
try {
// Set classloader before opening archive to enable
// validation.
AppClientArchivist arch = new AppClientArchivist();
arch.setAnnotationProcessingRequested(true);
arch.setClassLoader(jcl);
// for class case, get default bundle
if (className!=null) {
appDesc = (ApplicationClientDescriptor) arch.getDefaultBundleDescriptor();
} else {
// for client jar case, do not process annotations.
// use AppClientArchivist.open(String) instead of
// AppClientArchivist.open(AbstractArchive) since the
// open(String) method calls validate.
appDesc = (ApplicationClientDescriptor) arch.open(appClientFile.getAbsolutePath());
}
if (className!=null) {
// post masssaging
AbstractArchive archive;
if (appClientFile.isDirectory()) {
archive = new FileArchive();
((FileArchive) archive).open(appClientFile.getAbsolutePath());
} else {
archive = new InputJarArchive();
((InputJarArchive) archive).open(appClientFile.getAbsolutePath());
}
if (appDesc.getMainClassName()==null || appDesc.getMainClassName().length()==0) {
appDesc.setMainClassName(className);
arch.processAnnotations(appDesc, archive);
// let's remove our appArgs first element since it was the app client class name
//...but only if this is not a Java Web Start launch.
if (mainClass==null && ! isJWS) {
appArgs.removeElementAt(0);
}
}
}
} catch (Throwable t) {
_logger.log(Level.WARNING,
"main.appclient_descriptors_failed", (displayName == null) ? mainClass : displayName);
throw t;
}
container = new AppContainer(appDesc, guiAuth);
}
if(container == null) {
_logger.log(Level.WARNING, "acc.no_client_desc",
(displayName == null) ? mainClass : displayName);
System.exit(1);
}
// Set the authenticator which is called back when a
// protected web resource is requested and authentication data is
// needed.
Authenticator.setDefault(new HttpAuthenticator(container));
// log a machine name, port number per Jagadesh's request
_logger.log(Level.INFO, "acc.orb_host_name", host);
_logger.log(Level.INFO, "acc.orb_port_number", port);
Properties props = new Properties();
props.put("org.omg.CORBA.ORBInitialHost", host);
props.put("org.omg.CORBA.ORBInitialPort", port);
String appMainClass = container.preInvoke(props);
cleanup.setAppContainer(container);
// load and invoke the real main of the application.
Class cl = null;
try {
cl = jcl.loadClass(appMainClass);
} catch (java.lang.ClassNotFoundException cnf) {
String errorMessage = localStrings.getString
("appclient.mainclass.not.found", appMainClass);
_logger.log(Level.WARNING, errorMessage);
throw cnf;
}
_logger.log(Level.INFO, "acc.load_app_class", appMainClass);
String[] applicationArgs = new String[appArgs.size()];
for(int sz = 0; sz < applicationArgs.length; sz++) {
applicationArgs[sz] = (String) appArgs.elementAt(sz);
}
// check if we are dealing with an application client containing
// service references... if this is the case, I need to explode
// the appclient jar file to be able to access its wsdl files
// with a URL (so that imports can work)
if (appDesc.hasWebServiceClients()) {
File moduleFile;
if (appDesc.getApplication()==null
|| appDesc.getApplication().isVirtual()) {
// this is a standalone module, I can do Wsdl file
// resolution directly on it.
moduleFile = appClientFile;
} else {
InputJarArchive earFile = new InputJarArchive();
earFile.open(appClientFile.getAbsolutePath());
String moduleName = appDesc.getModuleDescriptor().getArchiveUri();
InputStream is = earFile.getEntry(moduleName);
moduleFile = File.createTempFile("appclient", ".jar");
moduleFile.deleteOnExit();
OutputStream os = new FileOutputStream(moduleFile);
ArchivistUtils.copy(new BufferedInputStream(is), new BufferedOutputStream(os));
earFile.close();
}
// now perform wsdl file resolution
for (Iterator itr = appDesc.getServiceReferenceDescriptors().iterator();
itr.hasNext();) {
ServiceReferenceDescriptor serviceRef = (ServiceReferenceDescriptor) itr.next();
if (serviceRef.getWsdlFileUri()!=null) {
// In case WebServiceRef does not specify wsdlLocation, we get wsdlLocation from @WebClient
// in wsimport generated source; If wsimport was given a local WSDL file, then WsdlURI will
// be an absolute path - in that case it should not be prefixed with modileFileDir
File wsdlFile = new File(serviceRef.getWsdlFileUri());
if(wsdlFile.isAbsolute()) {
serviceRef.setWsdlFileUrl(wsdlFile.toURI().toURL());
} else {
// This is the case where WsdlFileUri is a relative path (hence relative to the root of
// this module or wsimport was executed with WSDL in HTTP URL form
serviceRef.setWsdlFileUrl(FileUtil.getEntryAsUrl(moduleFile, serviceRef.getWsdlFileUri()));
}
}
}
}
// Inject the application client's injectable resources. This
// must be done after java:comp/env is initialized but before
// the application client's main class is invoked.
InjectionManager injMgr = Switch.getSwitch().getInjectionManager();
injMgr.injectClass(cl, appDesc);
if(runClient) {
Utility.invokeApplicationMain(cl, applicationArgs);
_logger.info("Application main() finished normally");
}
// inject the pre-destroy methods before shutting down
injMgr.invokeClassPreDestroy(cl, appDesc);
// Let's shutdown all the system resource adapters that are
// active in the container.
shutDownSystemAdapters();
// System.exit is not called if application main returned
// without error. Registered shutdown hook will perform
// container cleanup
} catch (java.lang.reflect.InvocationTargetException ite) {
Throwable tt = ite.getTargetException();
_logger.log(Level.WARNING, "acc.app_exception", tt);
shutDownSystemAdapters();
System.exit(1);
} catch (Throwable t) {
if (t instanceof javax.security.auth.login.FailedLoginException){
_logger.info("acc.login_error");
boolean isGui =
Boolean.valueOf
(System.getProperty ("auth.gui","true")).booleanValue();
String errorMessage =
localStrings.getString
("main.exception.loginError",
"Incorrect login and/or password");
if (isGui) {
GUIErrorDialog ged = new GUIErrorDialog (errorMessage);
ged.show ();
}
}
_logger.log(Level.WARNING, "acc.app_exception", t);
if (t instanceof javax.naming.NamingException) {
_logger.log(Level.WARNING, "acc.naming_exception_received");
}
shutDownSystemAdapters();
System.exit(1);
}
}
private static void setTargetServerProperties(String clientXmlLocation)
throws ConfigException {
//FIXME: may need to set the context in switch or generic context. but later
try {
if(clientXmlLocation == null || clientXmlLocation.equals("")) {
clientXmlLocation = DEFAULT_CLIENT_CONTAINER_XML;
}
// set for com.sun.enterprise.security.jauth.ConfigXMLParser
System.setProperty(SUNACC_XML_URL, clientXmlLocation);
_logger.log(Level.INFO, "acc.using_xml_location", clientXmlLocation);
ConfigContext ctx = ConfigFactory.createConfigContext(
clientXmlLocation, true,
false, false,
ClientContainer.class,
new ACCEntityResolver());
ClientContainer cc = ClientBeansFactory.getClientBean(ctx);
host = cc.getTargetServer(0).getAddress();
port = cc.getTargetServer(0).getPort();
//check for targetServerEndpoints
TargetServer[] tServer = cc.getTargetServer();
String targetServerEndpoints = null;
for (int i = 0; i < tServer.length; i++) {
if (targetServerEndpoints == null) {
targetServerEndpoints = tServer[i].getAddress() +
":" + tServer[i].getPort();
} else {
// if we come here, that means we have more than 1 target-server elements.
// in that case FOLB should be enabled
lb_enabled = true;
targetServerEndpoints = targetServerEndpoints + "," +
tServer[i].getAddress() +
":" + tServer[i].getPort();
}
}
setSSLData(cc);
//FIXME: what do we do about realm
ClientCredential cCrd = cc.getClientCredential();
if(cCrd != null) {
String uname = null;
String upass = null;
// if user entered user/password from command line,
// it take percedence over the xml file. - y.l. 05/15/02
if (System.getProperty(LOGIN_NAME) == null) {
_logger.config("using login name from client container xml...");
//System.setProperty(LOGIN_NAME, cCrd.getUserName());
uname = cCrd.getUserName();
}
if (System.getProperty(LOGIN_PASSWORD) == null) {
_logger.config("using password from client container xml...");
// System.setProperty(LOGIN_PASSWORD, cCrd.getPassword());
upass = cCrd.getPassword();
}
if( uname != null || upass != null ) {
UsernamePasswordStore.set(uname, upass);
}
}
String endpoints_property = null;
// Check if client requires SSL to be used
ElementProperty[] props = cc.getElementProperty();
for ( int i=0; i<props.length; i++ ) {
if ( props[i].getName().equals("ssl") ) {
if ( props[i].getValue().equals("required") ) {
(ORBManager.getCSIv2Props()).put(ORBManager.ORB_SSL_CLIENT_REQUIRED,
"true");
}
}
if ( props[i].getName().equals(S1ASCtxFactory.LOAD_BALANCING_PROPERTY) ) {
System.setProperty(props[i].getName(),props[i].getValue());
lb_enabled = true;
}
if ( props[i].getName().equals(S1ASCtxFactory.IIOP_ENDPOINTS_PROPERTY) ) {
endpoints_property = props[i].getValue().trim();
lb_enabled = true;
}
}
/*
*If the endpoints property was not set in the XML file's property
*settings, try to set it from the server's assignment in the JNLP document.
*/
String jwsEndpointsProperty = System.getProperty(Main.APPCLIENT_IIOP_FAILOVER_ENDPOINTS_PROPERTYNAME);
if (jwsEndpointsProperty != null) {
targetServerEndpoints = jwsEndpointsProperty;
lb_enabled = true;
} else {
/*
*Suppress the warning if the endpoints_property was set
*from the JNLP document, since that is in fact the preferred
*way to set the endpoints.
*/
_logger.warning("acc.targetserver.endpoints.warning");
}
_logger.fine("targetServerEndpoints = " + targetServerEndpoints +
"endpoints_property = " +
endpoints_property);
if (lb_enabled == true && endpoints_property == null) {
System.setProperty(
S1ASCtxFactory.IIOP_ENDPOINTS_PROPERTY,
targetServerEndpoints.trim());
} else if (endpoints_property != null) {
System.setProperty(
S1ASCtxFactory.IIOP_ENDPOINTS_PROPERTY,
targetServerEndpoints.trim() + "," +
endpoints_property);
}
} catch (ConfigException t) {
_logger.log(Level.WARNING,"acc.acc_xml_file_error" ,
new Object[] {clientXmlLocation, t.getMessage()});
_logger.log(Level.FINE, "exception : " + t.toString(), t);
throw t;
}
}
private static void setSSLData(ClientContainer cc) {
try {
// Set the SSL related properties for ORB
TargetServer tServer = cc.getTargetServer(0);
// TargetServer is required.
//temp solution to target-server+ change in DTD
// assuming that multiple servers can be specified but only 1st
// first one will be used.
Security security = tServer.getSecurity();
if (security == null) {
_logger.fine("No Security input set in ClientContainer.xml");
// do nothing
return;
}
Ssl ssl = security.getSsl();
if (ssl == null) {
_logger.fine("No SSL input set in ClientContainer.xml");
// do nothing
return;
}
//XXX do not use NSS in this release
//CertDb certDB = security.getCertDb();
SSLUtils.setAppclientSsl(ssl);
} catch (Exception ex) {
}
}
private static void validateXMLFile(String xmlFullName)
{
//<Bug # 4689278-Start>
if(xmlFullName == null ||
xmlFullName.startsWith("-")){ // If no file name is given after -xml argument
usage();
}
try {
File f = new File(xmlFullName);
if((f != null) && f.exists() && f.isFile() && f.canRead()){
return;
}else{// If given file does not exists
xmlMessage(xmlFullName);
usage();
}
} catch (Exception ex) {
xmlMessage(xmlFullName);
usage();
}
//</Bug # 4689278-End>
}
// Shut down system resource adapters. Currently it is
// only JMS.
private void shutDownSystemAdapters() {
try {
com.sun.enterprise.PoolManager poolmgr =
Switch.getSwitch().getPoolManager();
if ( poolmgr != null ) {
Switch.getSwitch().getPoolManager().killFreeConnectionsInPools();
}
} catch( Exception e ) {
//ignore
}
try {
ConnectorRegistry registry = ConnectorRegistry.getInstance();
ActiveResourceAdapter activeRar = registry.getActiveResourceAdapter
(ConnectorRuntime.DEFAULT_JMS_ADAPTER);
if (activeRar != null) {
activeRar.destroy();
}
} catch (Exception e) {
// Some thing has gone wrong. No problem
_logger.fine("Exception caught while shutting down system adapter:"+e.getMessage());
}
}
private static void usage() {
System.out.println(localStrings.getString("main.usage",
"appclient [ -client <appjar> ] [-mainclass <appClass-name>|-name <display-name>] [-xml <xml>] [-textauth] [-user <username>] [-password <password>|-passwordfile <password-file>] [app-args]"));
System.exit(1);
}
private static void xmlMessage(String xmlFullName)
{
System.out.println(localStrings.getString("main.cannot_read_clientContainer_xml", xmlFullName,
"Client Container xml: " + xmlFullName + " not found or unable to read.\nYou may want to use the -xml option to locate your configuration xml."));
}
private String loadPasswordFromFile(String fileName)
throws IOException {
InputStream inputStream = null;
try {
inputStream = new BufferedInputStream(new FileInputStream(fileName));
Properties props = new Properties();
props.load(inputStream);
return props.getProperty("PASSWORD");
} finally {
if (inputStream != null) {
inputStream.close();
}
}
}
private static class Cleanup extends Thread {
private AppContainer appContainer = null;
private boolean cleanedUp = false;
public Cleanup() {
}
public void setAppContainer(AppContainer container) {
appContainer = container;
}
public void run() {
cleanUp();
}
public void cleanUp() {
if( !cleanedUp ) {
try {
if( appContainer != null ) {
appContainer.postInvoke();
}
}
catch(Throwable t) {
}
finally {
cleanedUp = true;
}
} // End if -- cleanup required
}
}
/**
*Sets up the user-provided or default sun-acc.xml and
*wss-client-config.xml configurations.
*@return the file name of the sun-acc.xml file
*/
private String prepareJWSConfig() throws IOException, FileNotFoundException {
return prepareJWSDefaultConfig();
}
/**
*Creates temporary files for use as default sun-acc.xml and
*wss-client-config.xml configurations.
*@return the file name of the temporary sun-acc.xml file
*/
private String prepareJWSDefaultConfig() throws IOException, FileNotFoundException {
String result = null;
/*
*Retrieve the sun-acc and wss-client-config templates.
*/
String sunACCTemplate = Util.loadResource(this.getClass(), SUN_ACC_DEFAULT_TEMPLATE);
String wssClientConfigTemplate = Util.loadResource(this.getClass(), WSS_CLIENT_CONFIG_TEMPLATE);
/*
*Prepare the property names and values for substitution in the templates. Some
*of the properties are specified in the environment already, so use those
*as defaults and just add the extra ones.
*/
Properties tokenValues = new Properties(System.getProperties());
/**
*Create the wss client config defaults, then write them to a temporary file.
*/
String wssClientConfig = Util.replaceTokens(wssClientConfigTemplate, tokenValues);
File wssClientConfigFile = Util.writeTextToTempFile(wssClientConfig, WSS_CLIENT_CONFIG_PREFIX, WSS_CLIENT_CONFIG_SUFFIX, retainTempFiles);
pendingLogFine.append("Temporary wss-client-config.xml file: " + wssClientConfigFile.getAbsolutePath() + lineSep);
/*
*Now that the wss temp file is created, insert its name into the default
*sun-acc text and write that to another temp file.
*
*On Windows, the backslashes in the path will be consumed by the replaceTokens method which will
*interpret them as quoting the following character. So replace each \ with \\ first. All the slashes
*have to do with quoting a slash to the Java compiler, then quoting it again to the regex
*processor.
*/
String quotedConfigFileSpec = wssClientConfigFile.getAbsolutePath().replaceAll("\\\\", "\\\\\\\\");
tokenValues.setProperty(SUN_ACC_SECURITY_CONFIG_PROPERTY, quotedConfigFileSpec);
String sunaccContent = Util.replaceTokens(sunACCTemplate, tokenValues);
File sunaccFile = Util.writeTextToTempFile(sunaccContent, SUN_ACC_PREFIX, SUN_ACC_SUFFIX, retainTempFiles);
pendingLogFine.append("Temporary sun-acc.xml file: " + sunaccFile.getAbsolutePath());
return sunaccFile.getAbsolutePath();
}
/**
*Prepares the JAAS login configuration for a Java Web Start invocation.
*
*/
private void prepareJWSLoginConfig() throws IOException, FileNotFoundException {
prepareJWSDefaultLoginConfig();
}
/**
*Extracts the default login.conf file into a temporary file and assigns the
*java.security.auth.login.config property accordingly.
*/
private void prepareJWSDefaultLoginConfig() throws IOException, FileNotFoundException {
String configContent = Util.loadResource(this.getClass(), LOGIN_CONF_TEMPLATE);
File configFile = Util.writeTextToTempFile(configContent, LOGIN_CONF_FILE_PREFIX, LOGIN_CONF_FILE_SUFFIX, retainTempFiles);
String configFilePath = configFile.getAbsolutePath();
pendingLogFine.append("Temporary appclientlogin.conf file: " + configFilePath);
System.setProperty(LOGIN_CONF_PROPERTY_NAME, configFilePath);
}
/**
*Locate the app client jar file during a Java Web Start launch.
*@return File object for the client jar file
*/
private File findAppClientFileForJWSLaunch() throws ClassNotFoundException, URISyntaxException {
/*
*Locate the file by using the name of the "probe" class, passed from the
*server, to load the class and then find the location of the jar that
*contains that class.
*/
String probeClassName = System.getProperty(APPCLIENT_PROBE_CLASSNAME_PROPERTYNAME);
_logger.fine("Probing class " + probeClassName);
Class probeClass = Class.forName(probeClassName);
URL workingURL = probeClass.getProtectionDomain().getCodeSource().getLocation();
_logger.fine("Location of appclient jar file: " + workingURL.toString());
/*
*workingURL.toURI() on Windows gives (for example) file:c:/<rest of URI>.
*This cannot be used directly in new File(workingURI) because File complains
*that the URI is not hierarchical - it is missing the / that would
*normally precede the device. So, get the scheme-specific part and
*use that in the File constructor, which gives us the result we need.
*/
URI workingURI = workingURL.toURI();
String ssp = workingURI.getSchemeSpecificPart();
return new File(ssp);
}
}