Package com.sun.enterprise.management.support

Source Code of com.sun.enterprise.management.support.Loader$DeferredRegistrationThread

/*
* 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.management.support;

import java.util.List;
import java.util.Set;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.Iterator;
import java.io.IOException;

import java.lang.reflect.Proxy;

import javax.management.ObjectName;
import javax.management.MBeanServer;
import javax.management.Notification;
import javax.management.MBeanServerNotification;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.InstanceAlreadyExistsException;
import javax.management.NotCompliantMBeanException;

import javax.management.relation.MBeanServerNotificationFilter;


import com.sun.appserv.management.base.XTypes;
import com.sun.appserv.management.base.Util;

import com.sun.appserv.management.util.jmx.stringifier.NotificationStringifier;
import com.sun.appserv.management.util.jmx.JMXUtil;
import com.sun.appserv.management.util.jmx.MBeanProxyHandler;
import com.sun.appserv.management.util.jmx.MBeanServerConnectionSource;
import com.sun.appserv.management.util.jmx.stringifier.StringifierRegistryIniter;

import com.sun.appserv.management.util.misc.ExceptionUtil;
import com.sun.appserv.management.util.misc.GSetUtil;

import com.sun.appserv.management.util.stringifier.StringifierRegistryIniterImpl;
import com.sun.appserv.management.util.stringifier.StringifierRegistryImpl;

import com.sun.appserv.management.DomainRoot;
import com.sun.appserv.management.client.ProxyFactory;

import com.sun.enterprise.management.support.TypeInfos;
import com.sun.enterprise.management.DomainRootImpl;

import com.sun.enterprise.admin.common.ObjectNames;

import com.sun.enterprise.util.FeatureAvailability;

/**
  Implements loading of all MBean API MBeans WITHIN the DAS (Domain Admin Server).
*/
public final class Loader extends LoaderBase
{
  private boolean                  mQueuedAll;
  private List<LoaderOfOld>      mLoaders;
  private Map<ObjectName,ObjectName>  mOldToNewObjectNames;
  private LoaderRegThread             mRegThread;
 
    private final Set<String> JMX_DOMAINS_OF_INTEREST;

  private final DeferredRegistrationThread  mDeferredRegistrationThread;
 
    public
  Loader()
  {
        JMX_DOMAINS_OF_INTEREST =
            GSetUtil.newUnmodifiableStringSet( ObjectNames.kDefaultIASDomainName );
       
    mOldToNewObjectNames  =
        Collections.synchronizedMap( new HashMap<ObjectName,ObjectName>() );
   
    mQueuedAll  = false;
   
    mLoaders  = null;
   
    mRegThread      = null;
   
    mDeferredRegistrationThread  = new DeferredRegistrationThread();
    mDeferredRegistrationThread.start();
       
  }
 
      protected void
  preRegisterHook()
  {
    mRegThread  = LoaderRegThread.createInstance( this, mLogger );
    mRegThread.start();
  }
   
        protected final void
    postRegisterHook()
    {
        super.postRegisterHook();
       
        FeatureAvailability.getInstance().registerFeature(
            FeatureAvailability.AMX_LOADER_FEATURE, getObjectName() );
    }
   
    public void
  handleNotification(
    final Notification  notifIn,
    final Object    handback)
  {       
    final String  type  = notifIn.getType();
   
    if ( notifIn instanceof MBeanServerNotification )
    {
      final MBeanServerNotification  notif  = (MBeanServerNotification)notifIn;
      final ObjectName objectName  = notif.getMBeanName();
           
            if ( type == MBeanServerNotification.REGISTRATION_NOTIFICATION )
            {
                /*
                if ( JMXUtil.toString(objectName).equals( "amx:j2eeType=J2EEServer,name=server" ) )
                {
                   debug( "Loader.handleNotification:  REGISTER for: " + JMXUtil.toString(objectName) + "\n" + ExceptionUtil.toString( new Exception("foo") ) );
                }
                */
            }
            else if ( type == MBeanServerNotification.UNREGISTRATION_NOTIFICATION )
            {
                //debug( "Loader.handleNotification:  UNREGISTER for: " + JMXUtil.toString(objectName) );
            }
           
      if ( JMX_DOMAINS_OF_INTEREST.contains( objectName.getDomain() ) &&
                    shouldSync( objectName ) )
      {
        final boolean  register  =
          type == MBeanServerNotification.REGISTRATION_NOTIFICATION;
               
                // put it at the end of the registration or unregistration queue
        try
                {
                    mRegThread.enqueue( register, objectName );
                }
                catch( final InterruptedException e )
                {
                    // squelch, JMX can't do anything about it
                    logSevere( "InterruptedException trying to register/unregister MBean: " +
                        objectName + ":\n" + ExceptionUtil.toString(e) );
                }
      }
    }
  }
 
  private static final long  WAIT_THRESHOLD_MILLIS  = 5 * 1000// 5 seconds
 
    // might not be needed; see dependent code
    private static final boolean    WAIT_FOR_REGISTRATION = false;
   
    public void
  handleMBeanRegistered( final ObjectName  oldObjectName )
    throws InstanceNotFoundException
  {
    trace( "handleMBeanRegistered: " + oldObjectName );
   
    if ( shouldSync( oldObjectName ) )
    {
      final long  start  = now();
     
            if ( WAIT_FOR_REGISTRATION )
            {
                while ( ! getMBeanServer().isRegistered( oldObjectName ) &&
                        (now() - start) < WAIT_THRESHOLD_MILLIS )
                {
                    mySleep( 50 );
                    debug( "SLEPT for 50ms waiting for " + oldObjectName );
                }
            }
     
      if ( ! getMBeanServer().isRegistered( oldObjectName ) )
      {
        trace( "Loader.handleMBeanRegistered: not found: " + JMXUtil.toString(oldObjectName) );
        throw new InstanceNotFoundException( JMXUtil.toString(oldObjectName) );
      }
     
      try
      {
        sync( oldObjectName );
      }
      catch( Exception e )
      {
        final Throwable  rootCause  = ExceptionUtil.getRootCause( e );
        if ( rootCause instanceof DeferRegistrationException )
        {
          mDeferredRegistrationThread.defer( oldObjectName );
        }
      }
    }
  }
 
  /**
    Cascaded MBeans are problematic because some of them get registered before
    MBeans that contain them.  For most MBeans this is a non-issue, but the workaround
    code in LoaderOfOldMonitor.MyOldTypes.oldTypeToJ2EEType() can't deal with this situation,
    thus this facility exists to allow retry of problematically-registered MBeans.
   
    The need will go away if the underlying monitoring MBeans are fixed so that the workaround
    code is no longer needed.
   */
  private final class DeferredRegistrationThread extends Thread
  {
    private final List<DeferredItem>  mDeferredItems;
    private boolean    mSleeping;
   
    private final class DeferredItem
    {
      public long          mStartMillis;
      public final ObjectName    mObjectName;
     
        public
      DeferredItem( final ObjectName objectName )
      {
        mObjectName    = objectName;
        mStartMillis  = now();
      }
    };
   
    private final long  RETRY_INTERVAL_MILLIS   = 4000;
    private final long  MAX_DELAY_MILLIS      = 1 * 30 * 1000;
   
      public
    DeferredRegistrationThread( )
    {
      mDeferredItems  = Collections.synchronizedList( new ArrayList<DeferredItem>() );
     
      mSleeping  = false;
    }
   
      private synchronized void
    internalDefer( final DeferredItem item )
    {
      // even though it's a synchronized List, we still need to do this because
      // takeAllItems() needs to be able to make an array the clearing the list,
      // which is two operations.
      synchronized( mDeferredItems )
      {
        mDeferredItems.add( item );
      }
    }
   
      public synchronized void
    defer( final ObjectName oldObjectName )
    {
      logFine( "Deferring registration for " + quote( oldObjectName ) );
     
      internalDefer( new DeferredItem( oldObjectName ) );
     
      if ( mSleeping )
      {
        this.interrupt();
      }
     
    }
   
      private DeferredItem[]
    takeAllItems()
    {
      synchronized( mDeferredItems )
      {
        final DeferredItem[]  items  = new DeferredItem[ mDeferredItems.size() ];
        mDeferredItems.toArray( items );
        mDeferredItems.clear();
        return( items );
      }
    }
   
      private ObjectName
    retry( final ObjectName oldObjectName )
    {
      return sync( oldObjectName );
    }
   
   
      private void
    retryItem( final DeferredItem  item)
    {
      final ObjectName  oldObjectName  = item.mObjectName;
     
      final String  prefix  = "DeferredRegistrationThread.retryItem: ";
      final long  elapsed  = now() - item.mStartMillis;
      try
      {
        final ObjectName  result  = retry( oldObjectName );
       
        final String msg    = prefix + "deferred registration SUCCEEDED after " +
          elapsed + " milliseconds for " + quote( oldObjectName ) +
          ", amx ObjectName = " + quote( result );
         
        getMBeanLogger().info( msg );
      }
      catch( Throwable t )
      {
        final Throwable  rootCause  = ExceptionUtil.getRootCause( t );
       
        if ( rootCause instanceof DeferRegistrationException )
        {
          if ( elapsed < MAX_DELAY_MILLIS )
          {
            logWarning( prefix +
            "deferred registration RETRY failed after " +
              elapsed + " milliseconds for " + quote( oldObjectName ) + " (DEFERRING AGAIN)" );
            internalDefer( item );
          }
          else
          {
            logWarning( prefix +
              "Deferred registration FAILED for " + quote( oldObjectName ) +
              "after deferral of " + elapsed + " ms, ignoring MBean." );
          }
        }
        else
        {
          logWarning( prefix +
            "Deferred registration FAILED for " + quote( oldObjectName ) +
            "due to Exception of type " + rootCause.getClass().getName() );
        }
      }
    }
   
      private void
    checkList()
    {
      final DeferredItem[]  items  = takeAllItems();
     
      logFine( "DeferredRegistrationThread.checkList: numItems = " + items.length );
         
      for( int i = 0; i < items.length; ++i )
      {
        final DeferredItem  item  = items[ i ];
       
        if ( getMBeanServer().isRegistered( item.mObjectName ) )
        {
          retryItem( item );
        }
        else
        {
          logInfo(
            "DeferredRegistrationThread.checkList: " +
            "MBean is no longer registered: " + quote( item.mObjectName ) );
        }
      }
    }
   
      public void
    run()
    {
      while ( true )
      {
        try
        {         
          getMBeanLogger().fine( "DeferredRegistrationThread.run: CHECKING LIST@" + now() );
          checkList();
         
          // force a delay for efficiency in batching deferred items
          final long  sleepMillis  = mDeferredItems.size() == 0 ? 60 * 1000 : RETRY_INTERVAL_MILLIS;
          getMBeanLogger().fine( "DeferredRegistrationThread.run: SLEEPING FOR: " + sleepMillis + "@" + now()  );
          mSleeping  = true;
          final boolean  interrupted  = mySleep( sleepMillis );
          mSleeping  = false;
        }
        catch( Throwable t )
        {
          getMBeanLogger().warning( "DeferredRegistrationThread.run: caught Throwable:\n" +
            ExceptionUtil.getStackTrace( t ) );
        }
      }
    }
  }
 
    public void
  handleMBeanUnregistered( final ObjectName  oldObjectName )
    throws InstanceNotFoundException, MBeanRegistrationException
  {
    trace( "handleMBeanUnregistered: " + oldObjectName );
   
    final ObjectName  newObjectName  =
      mOldToNewObjectNames.remove( oldObjectName );
     
    if ( newObjectName != null && getMBeanServer().isRegistered( newObjectName ) )
    {
        debug( "unregistering: " + newObjectName + " corresponding to " + oldObjectName );
      getMBeanServer().unregisterMBean( newObjectName );
    }
  }
 
    synchronized ObjectName
  registerNew(
    final Object    impl,
    final ObjectName  implObjectName,
    final ObjectName  oldObjectName )
    throws MBeanRegistrationException,
      InstanceAlreadyExistsException, NotCompliantMBeanException
  {
    //debug( "registering: ", JMXUtil.toString(implObjectName), " corresponding to ", JMXUtil.toString(oldObjectName) );
       
    final ObjectName  resultName  =
      getMBeanServer().registerMBean( impl, implObjectName ).getObjectName();
     
    mOldToNewObjectNames.put( oldObjectName, resultName );
           
    return( resultName );
  }
         
    private void
  addLoaders()
  {
    assert( getMBeanServer() != null );
    assert( getMBeanLogger() != null );
   
    final List<LoaderOfOld>  loaders  = new ArrayList<LoaderOfOld>();
    loaders.add( new LoaderOfOldConfig( this ) );
    loaders.add( new LoaderOfOld77( this ) );
    loaders.add( new LoaderOfOldMonitor( this ) );
    mLoaders  = Collections.unmodifiableList( loaders );
  }
   

    private boolean
  shouldSync( final ObjectName oldObjectName )
  {
        final String  jmxDomain   = oldObjectName.getDomain();
        final boolean applicable  = ObjectNames.kDefaultIASDomainName.equals( jmxDomain );
       
    return applicable ? (findLoaderOfOld( oldObjectName ) != null) : false;
  }
 
    private LoaderOfOld
  findLoaderOfOld( final ObjectName candidate )
  {
    LoaderOfOld  oldLoader  = null;
   
    for( final LoaderOfOld loo : mLoaders )
    {
      if ( loo.shouldSync( candidate ) )
      {
        oldLoader  = loo;
        break;
      }
    }
    return( oldLoader );
  }

    private final Object CONFIG_SYNC  = new Object();
   
    public  final ObjectName
  sync( final ObjectName  oldObjectName )
  {
    if ( ! mStarted )
    {
      throw new IllegalStateException();
    }
       
    if ( ! shouldSync( oldObjectName ) )
    {
      throw new IllegalArgumentException( oldObjectName.toString() );
    }
       
        ObjectName  result = null;
        /*
            Synchronize for config; ConfigFactory can call sync() explicitly, and there
            is a race condition that can attempt duplicate registration with the
            one to be done or already done or in progress by handleMBeanRegistered().
         */
        final String category = oldObjectName.getKeyProperty( "category" );
        if ( category != null && category.equals( "config" ) )
        {
            synchronized( CONFIG_SYNC )
            {
               result = _sync( oldObjectName );
            }
        }
        else
        {
             result = _sync( oldObjectName );
        }
        return result;
    }
   
    private  ObjectName
  _sync( final ObjectName  oldObjectName )
  {
        if ( ! getMBeanServer().isRegistered( oldObjectName ) )
        {
      throw new RuntimeException( new InstanceNotFoundException() );
        }
       
        // out of order registration can result in trying to register the same MBean
        // more than once.
        synchronized( this )
        {
            ObjectName  result  = mOldToNewObjectNames.get( oldObjectName );
            if ( result == null )
            {
                try
                {
                    final LoaderOfOld  loaderOfOld  = findLoaderOfOld( oldObjectName );
                   
                    if ( loaderOfOld != null )
                    {
                        result  = loaderOfOld.syncWithOld( oldObjectName );
                        if ( result == null )
                        {
                            throw new IllegalArgumentException( oldObjectName.toString() );
                        }
                    }
                }
                catch( final Exception e )
                {
                    final Throwable rootCause = ExceptionUtil.getRootCause(e);
                    if ( rootCause instanceof InstanceNotFoundException )
                    {
                        // asynchronous registration makes this a  normal possibility
                        getMBeanLogger().info( "MBean disappeared during amx sync (ok): " + JMXUtil.toString(oldObjectName) );
                    }
                    else
                    {
                        final String msg    = ExceptionUtil.toString( e );
                        debug( msg );
                        getMBeanLogger().warning( msg );
                    }
                    if ( e instanceof RuntimeException )
                    {
                        throw (RuntimeException)e;
                    }
                    else
                    {
                        throw new RuntimeException( e );
                    }
                }
            }
   
            return( result );
        }
  }
 
    private void
  queueAll()
        throws InterruptedException
  {
    for( final LoaderOfOld oldLoader : mLoaders )
    {
      final List<ObjectName>  oldObjectNames  = oldLoader.findAllOld();
           
            // Note that some items could have been loaded already by virtue of having been created
            // between the time that listening started and queueAll() was called.  This is OK;
            // it will result in an InstanceAlreadyExistsException.
           
            mRegThread.enqueueAll( true, oldObjectNames );
     
      getMBeanLogger().fine( "Loader: Queued " + oldObjectNames.size() +
        " MBeans for loader " + oldLoader.getClass().getName() );
    }
  }
 
 
    protected void
  startHook()
  {
      super.startHook();
     
      addLoaders();
    try
        {
            queueAll();
        }
        catch( final InterruptedException e )
        {
            logSevere( "InterruptedException trying to register/unregister all MBeans: " + ExceptionUtil.toString(e) );
            throw new RuntimeException(e);
        }
       
        // set regardless of success; the attempt was made
        mQueuedAll  = true;
  }
 
    public boolean
  isStarted( )
  {
    return super.isStarted() && mQueuedAll &&
      mRegThread.isQueueEmpty();
  }
   
        public final void
    waitAll()
    {
        try
        {
            mRegThread.waitAll();
            debug( "waitAll() DONE" );
        }
        catch( InterruptedException e )
        {
            throw new RuntimeException(e);
        }
    }
 
      protected Object
    createDomainRoot()
    {
        return new DomainRootImpl();
    }
   
      public boolean
  isDAS()
  {
      return true;
  }
 
      public ObjectName
  resyncAMXMBean( final ObjectName amx )
      throws InstanceNotFoundException, MBeanRegistrationException
  {
      if ( ! getMBeanServer().isRegistered( amx ) )
      {
          throw new InstanceNotFoundException();
      }
      if ( ! getAMXJMXDomainName().equals( amx.getDomain() ) )
      {
          throw new IllegalArgumentException( "" + amx );
      }
     
      debug( "resyncAMXMBean: looking for matching delegate MBean" );
      ObjectName    old    = null;
      for( final ObjectName oldTemp : mOldToNewObjectNames.keySet() )
      {
          if ( mOldToNewObjectNames.get( oldTemp ).equals( amx ) )
          {
              old = oldTemp;
              debug( "resyncAMXMBean: found matching delegate MBean: " + old );
              break;
          }
      }
     
      if ( old == null )
      {
          throw new IllegalArgumentException( "" + amx );
      }
     
      debug( "resyncAMXMBean: removing mapping from: " + old + " TO " + amx );
        mOldToNewObjectNames.remove( old );
      debug( "resyncAMXMBean: unregistering: " + amx );
        getMBeanServer().unregisterMBean( amx );
      debug( "resyncAMXMBean: handleMBeanRegistered: " + amx );
        handleMBeanRegistered( old );
         
      final ObjectName    newAMX = mOldToNewObjectNames.get( old );
      assert( newAMX != null );
     
      debug( "resyncAMXMBean: new ObjectName: " + newAMX );
      return newAMX;
  }
 
}







TOP

Related Classes of com.sun.enterprise.management.support.Loader$DeferredRegistrationThread

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.