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

import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.HashMap;

import javax.management.ObjectName;
import javax.management.JMException;


import com.sun.enterprise.management.AMXTestBase;
import com.sun.enterprise.management.Capabilities;

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

import com.sun.appserv.management.config.CustomMBeanConfig;
import com.sun.appserv.management.config.DomainConfig;
import com.sun.appserv.management.config.PropertiesAccess;

import com.sun.enterprise.management.support.TestDummy;
import com.sun.enterprise.management.support.TestDummyMBean;

import com.sun.appserv.management.helper.RefHelper;

import com.sun.appserv.management.util.misc.CollectionUtil;

/**
 */
public final class CustomMBeanConfigTest extends AMXTestBase
{
    // built-into server already
    private static final String IMPL_CLASSNAME = TestDummy.class.getName();
        
    private static final String TEST_NAME_BASE = "custom";
    private static final String TEST_TYPE      = "CustomMBeanConfigTest";
    
		public
	CustomMBeanConfigTest ()
	{
	    if ( checkNotOffline( "ensureDefaultInstance" ) )
	    {
	        ensureDefaultInstance( getDomainConfig() );
	    }
	}
	
	   public static String
    getDefaultInstanceName()
    {
        return getDefaultInstanceName( "CustomMBeanConfig" );
    }
    
        public static CustomMBeanConfig
	ensureDefaultInstance( final DomainConfig domainConfig )
	{
	    CustomMBeanConfig   result  =
	        domainConfig.getCustomMBeanConfigMap().get( getDefaultInstanceName() );
	    
	    if ( result == null )
	    {
	        result  = createInstance( 
	            domainConfig,
	            getDefaultInstanceName(),
	            createProps() );
	    }
	    
	    return result;
	}
	
		public static CustomMBeanConfig
	createInstance(
	    final DomainConfig          domainConfig,
	    final String                name,
	    final Map<String,String> optional )
	{
	    final CustomMBeanConfig custom  =
	        domainConfig.createCustomMBeanConfig( name, IMPL_CLASSNAME,
	        createObjectName( name ),
	        false,
	        optional );
	    
	    return custom;
	}
	
	
		public Map<String,CustomMBeanConfig>
	getCustomMBeanConfigs()
	{
	    return getDomainConfig().getCustomMBeanConfigMap();
	}
	
		private void
	_testGetAll()
	{
	    final Map<String,CustomMBeanConfig> all = getCustomMBeanConfigs();
		assert( all != null );
	}
	
	    private void
	sanityCheck( final CustomMBeanConfig config )
	{
        final String    objectName = config.getObjectNameInConfig();
        
        final String    implClassname   = config.getImplClassname();
	}

		private synchronized void
	_testAttrs()
	{
	    final Map<String,CustomMBeanConfig> all = getCustomMBeanConfigs();
	    
	    if ( all.size() != 0 )
	    {
    	    // everything is already tested generically, but we'll
    	    // do some basic sanity checks here
    	    for( final CustomMBeanConfig config : all.values() )
    	    {
    	        sanityCheck( config );
    	    }
	    }
	    else
	    {
	        warning( "CustomMBeanConfigTest: No custom MBeans to test" );
	    }
	}
	

    /** 
        Create some dummy properties for creating a CustomMBeanConfig
     */
	    private static Map<String,String>
    createProps()
    {
	    final String PRP = PropertiesAccess.PROPERTY_PREFIX;    // shorten
	    
	    final Map<String,String> optional  = new HashMap<String,String>();
	    
	    // these must be available in test MBean
	    optional.put( PRP + "Attr1", "hello" );
	    optional.put( PRP + "Attr2", "world" );
	    
	    return optional;
    }
    
        private static String
    createObjectName( final String name )
    {
        return CustomMBeanConfig.JMX_DOMAIN + ":name=" + name +
            ",type=" + TEST_TYPE;
    }
	
		public synchronized CustomMBeanConfig
	create(
	    final DomainConfig          domainConfig,
	    final String                name,
	    final Map<String,String> optional )
	{
	    return createInstance( domainConfig, name, optional );
	}
	
		public synchronized void
	verifyPropsAdded(
	    final CustomMBeanConfig     config,
	    final Map<String,String>    props )
	{
	    for( final String key : props.keySet() )
	    {
	        if ( key.startsWith( PropertiesAccess.PROPERTY_PREFIX ) )
	        {
	            final String    specifiedValue   = props.get( key ).toString();
	            final String    propName    = key.substring(
	                PropertiesAccess.PROPERTY_PREFIX.length(), key.length());
	            
	            final String    actualValue = config.getPropertyValue( propName );
	            assert( specifiedValue.equals( actualValue ) );
	        }
	    }
	}


        private void
    removeCustomMBean( final String name )
    {
	    getDomainConfig().removeCustomMBeanConfig( name );
    }
    
        private Set<ObjectName>
    getRegisteredCustoms()
    {
	    final QueryMgr  queryMgr    = getQueryMgr();
	    final Set<ObjectName>   mbeans  =
	        queryMgr.queryPatternObjectNameSet( CustomMBeanConfig.JMX_DOMAIN, "type=" + TEST_TYPE );
	    
	    return mbeans;
    }
    
        private void
    unregisterAnyTestMBeans()
    {
        final Set<ObjectName>   customs = getRegisteredCustoms();
        for( final ObjectName objectName : customs )
        {
            if ( TEST_TYPE.equals( objectName.getKeyProperty( "type" ) ) )
            {
                try
                {
                    getMBeanServerConnection().unregisterMBean( objectName );
                    printVerbose( "unregistered: " + objectName );
                }
                catch( Exception e )
                {
                }
            }
        }
    }
	
		public synchronized void
	testCreateRemove()
	{
	    if ( ! checkNotOffline( "testCreateRemove" ) )
	    {
	        return;
	    }
	    
	    final DomainConfig  domainConfig    = getDomainConfig();
	    
	    final Map<String,String> optional    = createProps();
	    
	    final Set<CustomMBeanConfig>    created = new HashSet<CustomMBeanConfig>();
	    
	    final Map<String,CustomMBeanConfig> existing    =
	        getDomainConfig().getCustomMBeanConfigMap();
	    
	    unregisterAnyTestMBeans();
        final Set<ObjectName> customsBefore = getRegisteredCustoms();
	    if ( customsBefore.size() != 0 )
	    {
	        printVerbose( "custom MBeans already registered:\n" +
	            CollectionUtil.toString( customsBefore, "\n" ) );
	    }
	    
	    final int   NUM = 3;
	    for( int i = 0; i < NUM; ++i )
	    {
	        final String    testName    = TEST_NAME_BASE + i;
	        
	        if ( existing.containsKey( testName ) ) 
	        {
    	        RefHelper.removeAllRefsTo( existing.get( testName ), true );
	            // leftover from a failed test...
	            removeCustomMBean( testName );
	        }
	        
	        final CustomMBeanConfig config  =
	            create( domainConfig, TEST_NAME_BASE + i, optional );
	        //printVerbose( "created: " + Util.getObjectName( config ) );
	        
	        assert( getCustomMBeanConfigs().get( config.getName() ) == config );
	        
	        created.add( config );
	        sanityCheck( config );
	        
	        verifyPropsAdded( config, optional ); 
	    }
	    
	    _testGetAll();
	    _testAttrs();
	    
	    for( final CustomMBeanConfig config : created )
	    {
	        //printVerbose( "removing: " + Util.getObjectName( config ) );
	        final String    name    = config.getName();
	        removeCustomMBean( name );
	        
	        assert( getCustomMBeanConfigs().get( name ) == null );
	    }
	    
	    _testGetAll();
	    
	    mySleep( 100 );
        final Set<ObjectName>   customsAfter = getRegisteredCustoms();
        customsAfter.removeAll( customsBefore );
        if ( customsAfter.size() != 0 )
        {
            warning( "after removing custom MBeans, " +
                "they are still registered (not an AMX bug):\n" +
                CollectionUtil.toString( customsAfter, "\n" ) );
        }
        unregisterAnyTestMBeans();
	}
}






































