Package com.sun.appserv.management.client

Source Code of com.sun.appserv.management.client.AppserverConnectionSource

/*
* 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.
*/
/*
* $Header: /cvs/glassfish/appserv-api/src/java/com/sun/appserv/management/client/AppserverConnectionSource.java,v 1.2 2007/05/05 05:30:31 tcfujii Exp $
* $Revision: 1.2 $
* $Date: 2007/05/05 05:30:31 $
*/

package com.sun.appserv.management.client;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import java.io.IOException;
import java.io.File;

import java.net.MalformedURLException;

import java.security.KeyStore;
import javax.net.ssl.X509TrustManager;
import javax.net.ssl.HandshakeCompletedListener;

import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXConnectionNotification;
import javax.management.Notification;
import javax.management.NotificationListener;


import com.sun.appserv.management.client.ConnectionSource;
import com.sun.appserv.management.util.jmx.JMXConnectorConnectionSource;
import com.sun.appserv.management.util.misc.MapUtil;

import com.sun.appserv.management.DomainRoot;


/**
  Supports connectivity to Sun Appserver 8.1 and later (not available
  prior to 8.1).
  This is the only official way
  to get a connection to the appserver.
  <p>
  Helper methods to simplify connecting are available in
  {@link com.sun.appserv.management.helper.Connect}.
  <p>
  If the server is running with TLS enabled, then you must use the constructor
  that includes TLSParams. Here is an example of how to connect using TLS:
<pre>
final File trustStore  = new File( "~/.keystore" );
  final char[] trustStorePassword  = "changeme".toCharArray();  // or whatever it is
final HandshakeCompletedListener listener = new HandshakeCompletedListenerImpl();
final TrustStoreTrustManager trustMgr = new TrustStoreTrustManager( trustStore, trustStorePassword);
trustMgr.setPrompt( true );

final TLSParams  tlsParams = new TLSParams( new X509TrustManager[] { trustMgr }, listener );
final AppserverConnectionSource src  =
  new AppserverConnectionSource( AppserverConnectionSource.PROTOCOL_RMI,
    "localhost", 8686, "admin", "admin123",
    tlsParams,
    null );
final DomainRoot domainRoot  = src.getDomainRoot();
</pre>
  If security is not an  issue, it is recommended to simply disable TLS on the
  server.  However, you can also connect using TLS whereby the
  server certificate is blindly trusted:
<pre>
final TLSParams  tlsParams = new TLSParams( TrustAnyTrustManager.getInstanceArray(), null );
final AppserverConnectionSource src  =
  new AppserverConnectionSource( AppserverConnectionSource.PROTOCOL_RMI,
    "localhost", 8686, "admin", "admin123",
    tlsParams,
    null );
final DomainRoot domainRoot  = src.getDomainRoot();
</pre>
 
 
  @see com.sun.appserv.management.client.TrustStoreTrustManager
  @see com.sun.appserv.management.client.TrustAnyTrustManager
  @see com.sun.appserv.management.client.HandshakeCompletedListenerImpl
  @see com.sun.appserv.management.client.TLSParams
*/
public final class AppserverConnectionSource
  implements NotificationListener, ConnectionSource
{
  private final String      mHost;
  private final int        mPort;
  private final String      mProtocol;
  private final String      mUser;
  private final String      mPassword;
  private final TLSParams      mTLSParams;
  private final Map<String,String> mReserved;
 
  protected JMXConnector      mJMXConnector;
 
  /**
    FIXME FIXME FIXME
    This should be removed after the http connector supports the HandshakeCompletedListener
   */
  private static final boolean DISABLE_HANDSHAKE_COMPLETED_CHECK = true;

    private boolean
  disableHandShakeCompletedCheck()
  {
    return( DISABLE_HANDSHAKE_COMPLETED_CHECK && mProtocol.equals( PROTOCOL_HTTP ) );
  }
 
 
  /**
      @return true if the specified protocol is supported.
   */
    public static boolean
  isSupportedProtocol( final String protocol )
  {
    returnprotocol != null &&
        (
          protocol.equals( PROTOCOL_HTTP ) ||
          protocol.equals( PROTOCOL_RMI )
        )
      );
  }
 
 
  /**
    [used internally]
   */
  public final static String  TRUST_MANAGERS_KEY  = "TRUST_MANAGER_KEY";
 
  /**
    [used internally]
   */
  public final static String  HANDSHAKE_COMPLETED_LISTENER_KEY  = "HandshakeCompletedListener";
 
 
  private static final String  PROTOCOL_PREFIX  = "sun-as-";
 
  /**
    RMI protocol to the Appserver.
    <b>Do not use the literal value of this constant in your code;
    it is subject to change</b>
   */
  public final static String  PROTOCOL_RMI    = PROTOCOL_PREFIX + "rmi";
  /**
    Default protocol to the Appserver eg PROTOCOL_RMI.
   */
  public final static String  DEFAULT_PROTOCOL  = PROTOCOL_RMI;
 
  /**
    Internal unsupported protocol.  Not supported for external use.
    <b>Do not use the literal value of this constant in your code;
    it is subject to change</b>
   */
  public final static String  PROTOCOL_HTTP    = PROTOCOL_PREFIX + "http";
 
  private static final String  INTERNAL_HTTP  = "s1ashttp";
  private static final String  INTERNAL_HTTPS  = "s1ashttps";
 
  /**
    Packages for http(s) JMXConnectorProvider.
   */
  private final static String HTTP_FACTORY_PACKAGES  =
    "com.sun.enterprise.admin.jmx.remote.protocol";
 
  /**
     Name of the default TrustStore file, located in the client's
     home directory.
    
    */
  public static final String  DEFAULT_TRUST_STORE_NAME  = ".asadmintruststore";
 
  /**
    The default pasword for {@link #DEFAULT_TRUST_STORE_NAME}.
   */
  public static final String  DEFAULT_TRUST_STORE_PASSWORD  = "changeit";
 
  /**
    Create a new instance using the default protocol without TLS.
   
    @param host  hostname or IP address
    @param port  port to which to connect
    @param user username
    @param userPassword password for specified username
    @param reserved  reserved for future use
   */
    public
  AppserverConnectionSource(
    String    host,
    int      port,
    String    user,
    String    userPassword,
    final Map<String,String>  reserved)
  {
    this( DEFAULT_PROTOCOL, host, port, user, userPassword, reserved);
  }


  /**
    Create a new instance connecting to the specified host/port with
    the specified protocol without TLS.
    <p>
    <b>Note:</b>The only supported protocol is {@link #PROTOCOL_RMI}.
    Use of any other protocol is not supported and these protocols are
    subject to change or removal at any time.
   
    @param protocol protocol to use eg PROTOCOL_RMI
    @param host  hostname or IP address
    @param port  port to which to connect
    @param user username
    @param userPassword password for specified username
    @param reserved  reserved for future use
   */
    public
  AppserverConnectionSource(
    final String    protocol,
    final String    host,
    final int      port,
    final String    user,
    final String    userPassword,
    final Map<String,String>      reserved )
  {
    this ( protocol, host, port, user, userPassword, null, reserved );
  }
 
  /**
    Create a new instance which will use TLS for security if specified.
   
    @param protocol protocol to use eg PROTOCOL_RMI
    @param host  hostname or IP address
    @param port  port to which to connect
    @param user username
    @param userPassword password for specified username
    @param tlsParams (may be null if TLS is not desired)
    @param reserved  reserved for future use
   
    @see com.sun.appserv.management.client.TLSParams
   */
    public
  AppserverConnectionSource(
    final String    protocol,
    final String    host,
    final int      port,
    final String    user,
    final String    userPassword,
    final TLSParams    tlsParams,
    final Map<String,String> reserved )
  {
    if ( reserved != null && reserved.keySet().size() != 0 )
    {
      throw new IllegalArgumentException( "No parameters may be passed in 'reserved' Map" );
    }
   
    if ( isSupportedProtocol( protocol ) )
    {
      mHost    = host;
      mPort    = port;
      mProtocol  = protocol;
      mUser    = user;
      mPassword  = userPassword;
      mTLSParams  = tlsParams;
      mReserved  = reserved;
    }
    else
    {
      throw new IllegalArgumentException( "unsupported protocol: " + protocol +
        ", use either PROTOCOL_RMI or PROTOCOL_HTTP" );
    }
  }
 
    private Object
  envGet( final String key )
  {
    return( mReserved == null ? null : mReserved.get( key ) );
  }
 
    private final boolean
  useTLS()
  {
    return( mTLSParams != null  );
  }
 
    private final X509TrustManager[]
  getTrustManagers()
  {
    return( mTLSParams == null ? null : mTLSParams.getTrustManagers() );
  }
 
    private final HandshakeCompletedListener
  getSuppliedHandshakeCompletedListener()
  {
    return( mTLSParams == null ? null : mTLSParams.getHandshakeCompletedListener() );
  }
 
 
    private Map<String,Object>
  getCredentialsEnv(
    final String  user,
    final String  password )
  {
    final HashMap<String,Object>  env  = new HashMap<String,Object>();
     
    final String[]  credentials  = new String[] { mUser, mPassword };
   
    env.put( JMXConnector.CREDENTIALS, credentials );
   
    return( env );
  }
 
  private static final String  APPSERVER_JNDI_NAME  = "/management/rmi-jmx-connector";

    private void
  warning( final String msg )
  {
    System.out.println( "\n***\nWARNING: " + msg );
  }
 
    private JMXConnector
  createNew()
    throws MalformedURLException, IOException
  {
    final Map<String,Object>  env  = getCredentialsEnv( mUser, mPassword );
   
    // NetBeans fix; classloader must be more than system classloader
    env.put("jmx.remote.protocol.provider.class.loader",
      this.getClass().getClassLoader());

    final HandshakeCompletedListenerImpl  hcListener  =
      new HandshakeCompletedListenerImpl( getSuppliedHandshakeCompletedListener() );
   
    JMXServiceURL  url  = null;
    if ( mProtocol.equals( PROTOCOL_HTTP ) )
    {
      if ( useTLS() )
      {
        //env.put( TRUST_MANAGERS_KEY, getTrustManagers() );
                                final X509TrustManager[] tms = getTrustManagers();
                                if (tms != null && tms.length >= 1) {
                                    env.put( TRUST_MANAGERS_KEY, tms[0]);
                                }
        env.put( HANDSHAKE_COMPLETED_LISTENER_KEY, hcListener );
      }
     
      env.put( "com.sun.enterprise.as.http.auth", "BASIC" );
      env.put( "USER", mUser );
      env.put( "PASSWORD", mPassword );
      // so our JMXConnectorProvider may be found
      env.put( JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, HTTP_FACTORY_PACKAGES );
     
      final String  internalProtocol  = useTLS() ? INTERNAL_HTTPS : INTERNAL_HTTP;
      url  = new JMXServiceURL( internalProtocol, mHost, mPort);
    }
    else if ( mProtocol.equals( PROTOCOL_RMI ) )
    {
      if ( useTLS() )
      {
        // the only way we can communicate with/control the RMI stub is through
        // this special singleton class
        final AdminRMISSLClientSocketFactoryEnvImpl  rmiEnv  =
          AdminRMISSLClientSocketFactoryEnvImpl.getInstance();
        rmiEnv.setHandshakeCompletedListener( hcListener );
        rmiEnv.setTrustManagers( getTrustManagers() );
      }
     
      final String s = "service:jmx:rmi:///jndi/rmi://" +
        mHost + ":" + mPort  + APPSERVER_JNDI_NAME;
                        
      url  = new JMXServiceURL( s );
    }
    else
    {
      assert( false );
    }
   
    final JMXConnector conn  = JMXConnectorFactory.connect( url, env );
   
    /*
      If the connection was established with RMI, it could have been an insecure
      connection if a on-TLS stub was downloaded.  Verify that the
      a TLS Handshake was actually completed.
     */
    if ( ! disableHandShakeCompletedCheck() )
    {
      if ( useTLS() && hcListener.getLastEvent() == null )
      {
        conn.close();
        throw new IOException( "Connection could not be established using TLS; server is not using TLS" );
      }
    }
    else
    {
      //warning( "HandshakeCompletedCheck is temporarily disabled for PROTOCOL_HTTP" );
      /* This has been commented out -- See CR: 6172198. HTTPS/JMX Connector Implementation
      does not have to accept HandshakeCompletedListener for 8.1*/
    }
   
    conn.addConnectionNotificationListener( this, null, conn );
   
    return( conn );
  }
 
  /**
      Used internally as callback for {@link javax.management.NotificationListener}.
      <b>DO NOT CALL THIS METHOD</b>.
   */
    public void
  handleNotification(
    final Notification  notifIn,
    final Object    handback)
  {
    if ( notifIn instanceof JMXConnectionNotification )
    {
      final JMXConnectionNotification  notif  = (JMXConnectionNotification)notifIn;
     
      final String  type  = notif.getType();
   
      if ( type.equals( JMXConnectionNotification.FAILED) ||
        type.equals( JMXConnectionNotification.CLOSED ) )
      {
        mJMXConnector  = null;
      }
    }
  }
 
  /**
    If the connection has already been created, return the existing JMXConnector
    unless 'forceNew' is true or the connection is currently null.
   
    @param forceNew   if a new connection should be created
    @return JMXConnector
   */
    public JMXConnector
  getJMXConnector( final boolean forceNew )
    throws IOException
  {
    if ( forceNew || mJMXConnector == null )
    {
      mJMXConnector  = createNew();
      getMBeanServerConnection( false )// make sure it works...
    }
   
    return( mJMXConnector );
  }
 
 
    public MBeanServerConnection
  getExistingMBeanServerConnection( )
  {
    try
    {
      return( getJMXConnector( false ).getMBeanServerConnection() );
    }
    catch( IOException e )
    {
    }
    return( null );
  }
 
 
  /**
    @return getJMXConnector( forceNew ).getMBeanServerConnection()
   */
    public MBeanServerConnection
  getMBeanServerConnection( final boolean forceNew )
    throws IOException
  {
    return( getJMXConnector( forceNew ).getMBeanServerConnection() );
  }
 
    /**
        {@link DomainRoot} will be returned.  Upon return, AMX is
        ready for use.  If the server has just been started, there
        may be a slight delay until AMX is ready for use; this method
        returns only once AMX is ready for use.
      
        @return a DomainRoot
     */
    public DomainRoot
  getDomainRoot()
    throws IOException
  {
    final DomainRoot    domainRoot  =
        ProxyFactory.getInstance( this ).getDomainRoot( true );
   
    return domainRoot;
  }
 
    public String
  toString()
  {
    return(
      "protocol=" + mProtocol +
      ", host=" + mHost +
      ", port=" + mPort +
      ", user=" + mUser +
      ", useTLS={" + useTLS() + "}" +
      ", mReserved=" + (mReserved == null ? "null" : MapUtil.toString( mReserved )) );
  }
 

 
}
TOP

Related Classes of com.sun.appserv.management.client.AppserverConnectionSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.