/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.felix.scr.impl;


import java.util.*;

import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ManagedServiceFactory;
import org.osgi.service.component.*;
import org.osgi.service.log.LogService;


/**
 * The <code>ComponentFactoryImpl</code> TODO
 *
 * @author fmeschbe
 */
public class ComponentFactoryImpl extends AbstractComponentManager implements ComponentFactory, ManagedServiceFactory
{

    // The component registry used to retrieve component IDs
    private ComponentRegistry m_componentRegistry;

    // The map of components created from Configuration objects
    // maps PID to ComponentManager for configuration updating
    // this map is lazily created
    private Map m_configuredServices;

    // Actually we only use the identity key stuff, but there is
    // no IdentityHashSet and HashSet internally uses a HashMap anyway
    private Map m_createdComponents;


    ComponentFactoryImpl( BundleComponentActivator activator, ComponentMetadata metadata,
        ComponentRegistry componentRegistry )
    {
        super( activator, metadata, componentRegistry.createComponentId() );
        m_componentRegistry = componentRegistry;
        m_createdComponents = new IdentityHashMap();
    }


    /* (non-Javadoc)
     * @see org.osgi.service.component.ComponentFactory#newInstance(java.util.Dictionary)
     */
    public ComponentInstance newInstance( Dictionary dictionary )
    {
        return ( ComponentInstance ) createComponentManager( dictionary, true );
    }


    protected boolean createComponent()
    {
        // not component to create, newInstance must be used instead
        return true;
    }


    protected void deleteComponent()
    {
        // nothing to delete
    }


    protected ServiceRegistration registerComponentService()
    {
        log( LogService.LOG_DEBUG, "registering component factory", getComponentMetadata(), null );

        Dictionary serviceProperties = getProperties();
        return getActivator().getBundleContext().registerService( new String[]
            { ComponentFactory.class.getName(), ManagedServiceFactory.class.getName() }, getService(),
            serviceProperties );
    }


    public Object getInstance()
    {
        // this does not return the component instance actually
        return null;
    }


    public Dictionary getProperties()
    {
        Dictionary props = new Hashtable();

        // 112.5.5 The Component Factory service must register with the following properties
        props.put( ComponentConstants.COMPONENT_NAME, getComponentMetadata().getName() );
        props.put( ComponentConstants.COMPONENT_FACTORY, getComponentMetadata().getFactoryIdentifier() );

        // also register with the factory PID
        props.put( Constants.SERVICE_PID, getComponentMetadata().getName() );

        // descriptive service properties
        props.put( Constants.SERVICE_DESCRIPTION, "ManagedServiceFactory for Factory Component"
            + getComponentMetadata().getName() );
        props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );

        return props;
    }


    protected Object getService()
    {
        return this;
    }


    //---------- ManagedServiceFactory interface ------------------------------

    public void updated( String pid, Dictionary configuration )
    {
        ComponentManager cm;
        if ( m_configuredServices != null )
        {
            cm = ( ComponentManager ) m_configuredServices.get( pid );
        }
        else
        {
            m_configuredServices = new HashMap();
            cm = null;
        }

        if ( cm == null )
        {
            // create a new instance with the current configuration
            cm = createComponentManager( configuration, false );

            // keep a reference for future updates
            m_configuredServices.put( pid, cm );
        }
        else if ( cm instanceof ImmediateComponentManager )
        {
            // update the configuration as if called as ManagedService
            ( ( ImmediateComponentManager ) cm ).reconfigure( configuration );
        }
    }


    public void deleted( String pid )
    {
        if ( m_configuredServices != null )
        {
            ComponentManager cm = ( ComponentManager ) m_configuredServices.remove( pid );
            if ( cm != null )
            {
                log( LogService.LOG_DEBUG, "Disposing component after configuration deletion", getComponentMetadata(),
                    null );

                disposeComponentManager( cm );
            }
        }

    }


    public String getName()
    {
        return "Component Factory " + getComponentMetadata().getName();
    }


    //---------- internal -----------------------------------------------------

    /**
     * ComponentManager instances created by this method are not registered
     * with the ComponentRegistry. Therefore, any configuration update to these
     * components must be effected by this class !
     * 
     * @param configuration The (initial) configuration for the new
     *      component manager
     * @param isNewInstance <code>true</code> if this component manager is
     *      created as per {@link #newInstance(Dictionary)}. In this case the
     *      given configuration is used as the factory configuration and the
     *      component is immediately enabled (synchronously). Otherwise the
     *      component is created because a new configuration instance of
     *      this factory has been created. In this case the configuration is
     *      used as the normal configuration from configuration admin (not the
     *      factory configuration) and the component is enabled asynchronously.
     */
    private ComponentManager createComponentManager( Dictionary configuration, boolean isNewInstance )
    {
        long componentId = m_componentRegistry.createComponentId();
        ImmediateComponentManager cm = new ImmediateComponentManager( getActivator(), getComponentMetadata(),
            componentId );

        // add the new component to the activators instances
        getActivator().getInstanceReferences().add( cm );

        // register with the internal set of created components
        m_createdComponents.put( cm, cm );

        // inject configuration
        if ( isNewInstance )
        {
            cm.setFactoryProperties( configuration );
        }
        else
        {
            // this should not call component reactivation because it is
            // not active yet
            cm.reconfigure( configuration );
        }

        // enable synchronously or asynchronously depending on the flag
        cm.enable( isNewInstance );

        return cm;
    }


    private void disposeComponentManager( ComponentManager cm )
    {
        // remove from created components
        m_createdComponents.remove( cm );

        // remove from activators list
        getActivator().getInstanceReferences().remove( cm );

        // finally dispose it
        cm.dispose();
    }
}

@@ -3907,16 +3907,20 @@
 ENDOR, %22
+The 
 Apache S
@@ -5859,17 +5859,16 @@
 !%0A     *
- 
 %0A     * 

Fix name.