/**
 * Copyright  2001 The JA-SIG Collaborative.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the JA-SIG Collaborative
 *    (http://www.jasig.org/)."
 *
 * THIS SOFTWARE IS PROVIDED BY THE JA-SIG COLLABORATIVE "AS IS" AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE JA-SIG COLLABORATIVE OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

package org.jasig.portal;

import org.jasig.portal.layout.IUserLayoutManager;
import org.jasig.portal.layout.UserLayoutChannelDescription;
import org.jasig.portal.services.LogService;
import java.util.Map;

/**
 * A factory class that produces <code>IChannel</code> instances.
 *
 * @author <a href="mailto:pkharchenko@interactivebusiness.com">Peter Kharchenko</a>
 * @version $Revision$
 */
public class ChannelFactory {

    // table of multithreaded channels
    public static final java.util.Hashtable staticChannels=new java.util.Hashtable();

    /**
     * Instantiate a channel from information supplied by the user layout manager.
     *
     * @param channelSubscribeId a <code>String</code> value
     * @param ulm an <code>IUserLayoutManager</code> value
     * @param sessionId a <code>String</code> HTTP session Id value
     * @return an <code>IChannel</code> instance
     * @exception PortalException if an error occurs
     */
    public static IChannel instantiateLayoutChannel(String channelSubscribeId, IUserLayoutManager ulm, String sessionId) throws PortalException {
        // get channel information from the user layout manager
        UserLayoutChannelDescription channel=(UserLayoutChannelDescription) ulm.getNode(channelSubscribeId);
        if(channel!=null) {
            String className=channel.getClassName();
            String channelPublishId=channel.getChannelPublishId();
            long timeOut=channel.getTimeout();
            try {
                return instantiateChannel(channelSubscribeId,channelPublishId, className,timeOut,channel.getParameterMap(),sessionId);
            } catch (Exception ex) {
                LogService.instance().log(LogService.ERROR,"ChannelManager::instantiateChannel() : unable to instantiate channel class \""+className+"\". "+ex);
                return null;
            }
        } else return null;
    }

    /**
     * Construct channel instance based on a channel description object.
     *
     * @param description an <code>UserLayoutChannelDescription</code> value
     * @param sessionId a <code>String</code> HTTP session Id value
     * @return an <code>IChannel</code> value
     */
    public static IChannel instantiateLayoutChannel(UserLayoutChannelDescription description, String sessionId) throws PortalException {
        return instantiateChannel(description.getChannelSubscribeId(),description.getChannelPublishId(), description.getClassName(),description.getTimeout(),description.getParameterMap(),sessionId);
    }
    
    private static IChannel instantiateChannel(String channelSubscribeId, String channelPublishId, String className, long timeOut, Map params, String sessionId) throws PortalException {
        IChannel ch=null;
        
        boolean exists=false;
        // this is somewhat of a cheating ... I am trying to avoid instantiating a multithreaded
        // channel more then once, but it's difficult to implement "instanceof" operation on
        // the java.lang.Class. So, I just look into the staticChannels table.
        Object cobj=staticChannels.get(className);
        if(cobj!=null) {
            exists=true;
        } else {
            try {
                cobj =  Class.forName(className).newInstance();
            } catch (Exception e) {
                throw new PortalException("Unable to instantiate class \""+className+"\"",e);
            }
        }

        // determine what kind of a channel it is.
        // (perhaps, later this all could be moved to JNDI factories, so everything would be transparent)
        if(cobj instanceof IMultithreadedChannel) {
            String uid=sessionId+"/"+channelSubscribeId;
            if(cobj instanceof IMultithreadedCacheable) {
                if(cobj instanceof IPrivileged) {
                    // both cacheable and privileged
                    ch=new MultithreadedPrivilegedCacheableChannelAdapter((IMultithreadedChannel)cobj,uid);
                } else {
                    // just cacheable
                    ch=new MultithreadedCacheableChannelAdapter((IMultithreadedChannel)cobj,uid);
                }
            } else if(cobj instanceof IPrivileged) {
                ch=new MultithreadedPrivilegedChannelAdapter((IMultithreadedChannel)cobj,uid);
            } else {
                // plain multithreaded
                ch=new MultithreadedChannelAdapter((IMultithreadedChannel)cobj,uid);
            }
            // see if we need to add the instance to the staticChannels
            if(!exists) {
                staticChannels.put(className,cobj);
            }
        } else {
            // vanilla IChannel
            ch=(IChannel)cobj;
        }
        return ch;
    }
}

@@ -4110,20 +4110,16 @@
 ;%0A    %7D%0A
-    
 %0A    pri
@@ -4307,36 +4307,750 @@
     
-  IChannel ch=null;%0A        
+String uid = sessionId + %22/%22 + channelSubscribeId;%0A      return instantiateChannel(className, uid);%0A    %7D%0A%0A    /**%0A     * Produce an IChannel based on a java class name.  If the java class%0A     * specified implements a channel interface other than%0A     * %3Ccode%3Eorg.jasig.portal.IChannel%3C/code%3E, it will be wrapped by an%0A     * appropriate adapter class that does implement IChannel.%0A     * @param className the channel's java class name%0A     * @param uid a unique ID for use with multithreaded channels%0A     * @return an %3Ccode%3EIChannel%3C/code%3E object%0A     */%0A    public static IChannel instantiateChannel(String className, String uid) throws PortalException %7B%0A        IChannel ch=null;%0A        String staticChannelKey = className + %22_%22 + uid;%0A
 %0A   
@@ -5384,25 +5384,32 @@
 els.get(
-className
+staticChannelKey
 );%0A     
@@ -5920,65 +5920,8 @@
 ) %7B%0A
-            String uid=sessionId+%22/%22+channelSubscribeId;%0A
     
@@ -6804,25 +6804,32 @@
 els.put(
-className
+staticChannelKey
 ,cobj);%0A

Factored out a more basic instantiateChannel method that can be used by the web services code.