Package org.jasig.portal

Source Code of org.jasig.portal.ChannelManager

/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig 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.jasig.portal;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicLong;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.portal.channels.CSecureInfo;
import org.jasig.portal.channels.error.CError;
import org.jasig.portal.channels.error.ErrorCode;
import org.jasig.portal.channels.support.IDynamicChannelTitleRenderer;
import org.jasig.portal.events.EventPublisherLocator;
import org.jasig.portal.events.support.ChannelInstanciatedInLayoutPortalEvent;
import org.jasig.portal.events.support.ChannelRenderedInLayoutPortalEvent;
import org.jasig.portal.events.support.ChannelTargetedInLayoutPortalEvent;
import org.jasig.portal.events.support.PortletActionInLayoutPortalEvent;
import org.jasig.portal.i18n.LocaleManager;
import org.jasig.portal.jndi.IJndiManager;
import org.jasig.portal.layout.IUserLayout;
import org.jasig.portal.layout.IUserLayoutManager;
import org.jasig.portal.layout.LayoutEvent;
import org.jasig.portal.layout.LayoutEventListener;
import org.jasig.portal.layout.LayoutMoveEvent;
import org.jasig.portal.layout.node.IUserLayoutChannelDescription;
import org.jasig.portal.layout.node.IUserLayoutNodeDescription;
import org.jasig.portal.portlet.url.RequestType;
import org.jasig.portal.properties.PropertiesManager;
import org.jasig.portal.security.IAuthorizationPrincipal;
import org.jasig.portal.security.IPerson;
import org.jasig.portal.serialize.CachingSerializer;
import org.jasig.portal.services.AuthorizationService;
import org.jasig.portal.spring.PortalApplicationContextLocator;
import org.jasig.portal.spring.locator.ChannelRequestParameterManagerLocator;
import org.jasig.portal.spring.locator.JndiManagerLocator;
import org.jasig.portal.url.support.IChannelRequestParameterManager;
import org.jasig.portal.utils.SAX2BufferImpl;
import org.jasig.portal.utils.SetCheckInSemaphore;
import org.jasig.portal.utils.web.PortalWebUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.jndi.JndiTemplate;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.xml.sax.ContentHandler;

import tyrex.naming.MemoryContext;

/**
* ChannelManager shall have the burden of squeezing content out of channels.
* <p>
* Validation and timeouts, these two are needed for smooth operation of the portal
* sometimes channels will timeout with information retrieval then the content should
* be skipped.
*
* @author Peter Kharchenko, pkharchenko@unicon.net
* @version $Revision: 20117 $
* @deprecated IChannel rendering code will be replaced with portlet specific rendering code in a future release
*/
@Deprecated
public class ChannelManager implements LayoutEventListener {
    private static final String PORTAL_CONTROL_STRUCTURES_MAP_ATTR = ChannelManager.class.getName() + ".PortalControlStructuresMap";

    public static final String channelAddressingPathElement = "channel";

    // Metrics
    private static final AtomicLong activeRenderers = new AtomicLong();
    private static final AtomicLong maxRenderThreads = new AtomicLong();
   
    public static long getActiveRenderers() {
        return activeRenderers.get();
    }
   
    public static long getMaxRenderThreads() {
        return maxRenderThreads.get();
    }
   
    // Factory used to build all channel renderer objects.
    private static final IChannelRendererFactory cChannelRendererFactory =
        ChannelRendererFactory.newInstance(ChannelManager.class.getName(), activeRenderers, maxRenderThreads);
   
    private static boolean useAnchors = PropertiesManager.getPropertyAsBoolean("org.jasig.portal.ChannelManager.use_anchors", false);
   

    private static final Log log = LogFactory.getLog(ChannelManager.class);

    private final IUserPreferencesManager userPreferencesManager;
   
    // Channel rendering tables
    private final Map<String, IChannel> channelTable = new Hashtable<String, IChannel>();
    private final Map<String, IChannelRenderer> rendererTable = new Hashtable<String, IChannelRenderer>();
    private final Map<IChannel, Map<String, ChannelCacheEntry>> channelCacheTable = Collections.synchronizedMap(new WeakHashMap<IChannel, Map<String, ChannelCacheEntry>>());;

    // Tracks repeated rendering for an erroring channel
    private final Set<String> repeatRenderings = new HashSet<String>();

    // inter-channel communication tables
    private final Map<String, Set<String>> iccTalkers = new HashMap<String, Set<String>>();
    private final Map<String, Set<String>> iccListeners = new HashMap<String, Set<String>>();

    // JNDI Context reference for channels
    private final Context channelContext;

    // Used for channel authorization decisions
    private final IAuthorizationPrincipal authorizationPrincipal;

    // a set of channels requested for rendering, but
    // awaiting rendering set commit due to inter-channel
    // communication
    private final Set<String> pendingChannels = new HashSet<String>();

    private String channelTarget;
    private Map<String, Object> targetParams;
    private UPFileSpec uPElement;
   
    private boolean characterCaching = false;
    private BrowserInfo browserInfo;
    private LocaleManager localeManager;
    private String serializerName;
    private boolean groupedRendering = false;
   

    /**
     * Creates a new <code>ChannelManager</code> instance.
     *
     * @param manager an <code>IUserPreferencesManager</code> value
     */
    public ChannelManager(IUserPreferencesManager manager, HttpSession httpSession) {
        this.userPreferencesManager = manager;
       
       
        final String sessionId = httpSession.getId();
       
        final IPerson person = this.userPreferencesManager.getPerson();
        final String personId = Integer.toString(person.getID());
       
        final UserProfile currentProfile = this.userPreferencesManager.getCurrentProfile();
        final String layoutId = Integer.toString(currentProfile.getLayoutId());

        this.channelContext = this.getChannelJndiContext(sessionId, personId, layoutId);
       
       
        final EntityIdentifier personEntityIdentifier = person.getEntityIdentifier();
        this.authorizationPrincipal = AuthorizationService.instance().newPrincipal(personEntityIdentifier.getKey(), personEntityIdentifier.getType());
    }
   


    /**
     * <code>getChannelContext</code> generates a JNDI context that
     * will be passed to the regular channels. The context is pieced
     * together from the parts of the global portal context.
     *
     * @param portalContext uPortal JNDI context
     * @param sessionId current session id
     * @param userId id of a current user
     * @param layoutId id of the layout used by the user
     * @return a channel <code>InitialContext</code> value
     */
    private Context getChannelJndiContext(String sessionId, String userId, String layoutId) {
        final IJndiManager jndiManager = JndiManagerLocator.getJndiManager();
        final JndiTemplate jndiTemplate = jndiManager.getJndiTemplate();
       
        final Thread currentThread = Thread.currentThread();
        final ClassLoader contextClassLoader = currentThread.getContextClassLoader();
        try {
            //Switch to the portal classloader to ensure the JNDI lookup works
            final ClassLoader portalClassLoader = this.getClass().getClassLoader();
            currentThread.setContextClassLoader(portalClassLoader);
           
            // create a new InitialContext
            final Context cic = new MemoryContext(new Hashtable<Object, Object>());
            // get services context
            final Context servicesContext = (Context) jndiTemplate.lookup("services", Context.class);
            // get channel-ids context
            final Context channel_idsContext = (Context) jndiTemplate.lookup("users/" + userId + "/layouts/" + layoutId + "/channel-ids", Context.class);
            // get channel-obj context
            final Context channel_objContext = (Context) jndiTemplate.lookup("users/" + userId + "/sessions/" + sessionId + "/channel-obj", Context.class);
   
            cic.bind("services", servicesContext);
            cic.bind("channel-ids", channel_idsContext);
            cic.bind("channel-obj", channel_objContext);
            cic.bind("portlet-ids", new ArrayList<Object>());
   
            return cic;
        }
        catch (NamingException ne) {
            log.warn("Failed to create channel JNDI Context. No JNDI context will be available for inter-channel-communication.", ne);
            return null;
        }
        finally {
            currentThread.setContextClassLoader(contextClassLoader);
        }
    }
   
    private PortalControlStructures getPortalControlStructuresForChannel(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId) {
        Map<String, PortalControlStructures> existingPortalControlStructures;
        synchronized (PortalWebUtils.getRequestAttributeMutex(request)) {
            existingPortalControlStructures = (Map<String, PortalControlStructures>)request.getAttribute(PORTAL_CONTROL_STRUCTURES_MAP_ATTR);
            if (existingPortalControlStructures == null) {
                existingPortalControlStructures = new HashMap<String, PortalControlStructures>();
                request.setAttribute(PORTAL_CONTROL_STRUCTURES_MAP_ATTR, existingPortalControlStructures);
            }
        }
       
        synchronized (existingPortalControlStructures) {
            PortalControlStructures pcs = existingPortalControlStructures.get(channelSubscribeId);
            if (pcs == null) {
                pcs = new PortalControlStructures(request, response, this, this.userPreferencesManager);
                existingPortalControlStructures.put(channelSubscribeId, pcs);
            }
            return pcs;
        }
    }
   
    /**
     * Directly places a channel instance into the hashtable of active channels.
     * This is designed to be used by the error channel only.
     */
    public void setChannelInstance(String channelSubscribeId, IChannel channelInstance) {
        if (channelTable.get(channelSubscribeId) != null) {
            channelTable.remove(channelSubscribeId);
        }
        channelTable.put(channelSubscribeId, channelInstance);
    }

    /**
     * A method to notify <code>ChannelManager</code> that the channel set for
     * the current rendering cycle is complete.
     * Note: This information is used to identify relevant channel communication dependencies
     */
    public void commitToRenderingChannelSet() {
        if(groupedRendering) {
            // separate out the dependency group in s0

            Set<String> s0 = new HashSet<String>();
            Set<String> children;

            if (pendingChannels.contains(channelTarget)) {
                s0.add(channelTarget);
                pendingChannels.remove(channelTarget);
                children = getListeningChannels(channelTarget);
                if (children != null && !children.isEmpty()) {
                    children.retainAll(pendingChannels);
                    while (!children.isEmpty()) {
                        // move to the next generation
                        Set<String> newChildren = new HashSet<String>();
                        for (String childId : children) {
                            s0.add(childId);
                            pendingChannels.remove(childId);
                            Set<String> currentChildren = getListeningChannels(childId);
                            if (currentChildren != null) {
                                newChildren.addAll(currentChildren);
                            }
                        }
                        newChildren.retainAll(pendingChannels);
                        children = newChildren;
                    }
                }
            }

            // now s0 group must be synchronized at renderXML(), while the remaining pendingChildren can be rendered freely
            SetCheckInSemaphore s0semaphore= new SetCheckInSemaphore(new HashSet<String>(s0));
            for(Iterator<String> gi=s0.iterator();gi.hasNext();) {
                String channelSubscribeId=gi.next();
                IChannelRenderer cr=rendererTable.get(channelSubscribeId);
                cr.startRendering(s0semaphore,channelSubscribeId);
            }

            for(Iterator<String> oi=pendingChannels.iterator();oi.hasNext();) {
                String channelSubscribeId=oi.next();
                IChannelRenderer cr=rendererTable.get(channelSubscribeId);
                cr.startRendering();
            }
        }
    }


    /**
     * Clean up after a rendering round.
     */
    public void finishedRenderingCycle() {
        // clean up
        for (final IChannelRenderer channelRenderer : this.rendererTable.values()) {
            try {
                /*
                 * For well behaved, finished channel renderers, killing doesn't do
                 * anything.
                 *
                 * For runaway, not-finished channel renderers, killing instructs them to
                 * stop trying to render because at this point we can't use the
                 * results of their rendering anyway.  Furthermore, the current
                 * actual implementation
                 * of kill is for channel renderers to kill runaway threads.
                 */
                channelRenderer.kill();
            } catch (Throwable t) {
                /*
                 * We're trying to clean up.  A particular thread renderer we've asked
                 * to please die has failed to die in some potentially horrible way.
                 * This is unfortunate, but the best thing we can do about it is log
                 * the problem and then go on and ask the other ChannelRenderers to
                 * clean up.  If this one won't clean up properly, maybe at least some
                 * of the others will clean up.  By catching Throwable and handling
                 * it in this way, we prevent any particular ChannelRenderer's failure
                 * from blocking our asking other ChannelRenderers to clean up.
                 */
                log.error("Error cleaning up runaway channel renderer: [" + channelRenderer + "]", t);
            }

        }
        rendererTable.clear();
        repeatRenderings.clear();
        pendingChannels.clear();
       
        targetParams = null;
        groupedRendering = false;
    }


    /**
     * Handle end-of-session cleanup
     *
     */
    public void finishedSession(HttpSession session) {
        this.finishedRenderingCycle();
       
        final PortalControlStructures pcs = new PortalControlStructures(session, this, this.userPreferencesManager);

        // send SESSION_DONE event to all the channels
        final PortalEvent ev = PortalEvent.SESSION_DONE_EVENT;

        for (final IChannel ch : this.channelTable.values()) {
            if (ch != null) {
                try {
                    if (ch instanceof IPrivileged) {
                        ((IPrivileged) ch).setPortalControlStructures(pcs);
                    }

                    ch.receiveEvent(ev);
                }
                catch (Exception e) {
                    log.error("Error sending session done event to channel " + ch, e);
                }
            }
        }

        //Cleanup tables just to be nice
        channelTable.clear();
        channelCacheTable.clear();
        iccTalkers.clear();
        iccListeners.clear();
    }

    /**
     * Outputs a channel in to a given content handler.
     * If the current rendering cycle is targeting character
     * cache output, and the content handler passed to the method
     * is an instance of <code>CachingSerializer</code>, the method
     * will take care of character cache compilation and store cache
     * in the tables.
     *
     * @param channelSubscribeId a <code>String</code> value
     * @param contentHandler a <code>ContentHandler</code> value
     */
    public void outputChannel(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId, ContentHandler contentHandler) {
        // Set the subscribeId as the achorId for an anchoring serializer
        if (useAnchors && contentHandler instanceof IAnchoringSerializer) {
            IAnchoringSerializer as = (IAnchoringSerializer)contentHandler;
            as.startAnchoring(channelSubscribeId);
        }

        // obtain IChannelRenderer
        IChannelRenderer cr = rendererTable.get(channelSubscribeId);
        if (cr == null) {
            // channel rendering wasn't started ?
            try {
                if (log.isDebugEnabled()) {
                    log.debug("Getting output - no channel renderer for subscribe id: " + channelSubscribeId + ", starting rendering");
                }
                cr = startChannelRendering(request, response, channelSubscribeId);
            }
            catch (PortalException pe) {
                // record, and go on
                log.error("Encountered a portal exception while trying to start channel rendering! :", pe);
            }
        }
       
        if (log.isDebugEnabled()) {
            log.debug("Getting output - Retrieved channel renderer " + cr.toString() + " for subscribe id: " + channelSubscribeId);
        }

        // complete rendering and check status
        int renderingStatus=-1;
        try {
            renderingStatus=cr.completeRendering();
        } catch (Throwable t) {
            handleRenderingError(request, response, channelSubscribeId,contentHandler,t,renderingStatus,"encountered problem while trying to complete rendering","IChannelRenderer.completeRendering() threw",false);
            return;
        }

        if(renderingStatus==IChannelRenderer.RENDERING_SUCCESSFUL) {
            // obtain content
            if(contentHandler instanceof CachingSerializer && this.characterCaching) {
                CachingSerializer cs=(CachingSerializer) contentHandler;
                // need to get characters
                String characterContent=cr.getCharacters();
                if(characterContent==null) {
                    // obtain a SAX Buffer content then
                    SAX2BufferImpl bufferedContent=cr.getBuffer();
                    if(bufferedContent!=null) {
                        // translate SAX Buffer into the character version
                        try {
                            if(!cs.startCaching()) {
                                log.error("unable to restart character cache while compiling character cache for channel '"+channelSubscribeId+"' !");
                            }
                            // dump SAX buffer into the serializer
                            bufferedContent.outputBuffer(contentHandler);
                            // extract compiled character cache
                            if(cs.stopCaching()) {
                                try {
                                    characterContent=cs.getCache();
                                  log.debug("outputChannel 2: "+characterContent);
                                    if(characterContent!=null) {
                                        // save compiled character cache
                                        cr.setCharacterCache(characterContent);
                                    } else {
                                        log.error("character caching serializer returned NULL character cache for channel '"+channelSubscribeId+"' !");
                                    }
                                } catch (UnsupportedEncodingException e) {
                                    log.error("unable to compile character cache for channel '"+channelSubscribeId+"'! Invalid encoding specified.",e);
                                } catch (IOException ioe) {
                                    log.error("IO exception occurred while compiling character cache for channel '"+channelSubscribeId+"' !",ioe);
                                }
                            } else {
                                log.error("unable to reset cache state while compiling character cache for channel '"+channelSubscribeId+"' ! Serializer was not caching when it should've been ! Partial output possible!");
                                return;
                            }
                        } catch (IOException ioe) {
                            handleRenderingError(request, response, channelSubscribeId,contentHandler,ioe,renderingStatus,"encountered a problem compiling channel character content","Encountered IO exception while trying to output channel content SAX to the character caching serializer",true);
                            return;
                        } catch (org.xml.sax.SAXException se) {
                            handleRenderingError(request, response, channelSubscribeId,contentHandler,se,renderingStatus,"encountered a problem compiling channel character content","Encountered SAX exception while trying to output channel content SAX to the character caching serializer",true);
                            return;
                        }

                    } else {
                        handleRenderingError(request, response, channelSubscribeId,contentHandler,null,renderingStatus,"unable to obtain channel rendering","IChannelRenderer.getBuffer() returned null",false);
                        return;
                    }
                } else { // non-null characterContent case
                    // output character content
                    try {
                        if (log.isDebugEnabled()) {
                            log.debug("Getting output - Writing " + characterContent.length() + " characters for " + cr.toString() + " for subscribe id: " + channelSubscribeId);
                        }
                        cs.printRawCharacters(characterContent);
                    } catch (IOException ioe) {
                        if (log.isDebugEnabled())
                            log.debug("" +
                                    "exception thrown while trying to output character " +
                                    "cache for channelSubscribeId=" +
                                    "'"+channelSubscribeId + "'", ioe);
                    }
                }
            } else { // regular serializer case
                // need to output straight
                SAX2BufferImpl bufferedContent=cr.getBuffer();
                if(bufferedContent!=null) {
                    try {
                        // output to the serializer
                        ChannelSAXStreamFilter custodian = new ChannelSAXStreamFilter(contentHandler);
                        bufferedContent.outputBuffer(custodian);
                    } catch (Exception e) {
                        log.error("encountered an exception while trying to output SAX2 content of channel '"+channelSubscribeId+"' to a regular serializer. Partial output possible !",e);
                        return;
                    }
                } else {
                    handleRenderingError(request, response, channelSubscribeId,contentHandler,null,renderingStatus,"unable to obtain channel rendering","IChannelRenderer.getBuffer() returned null",false);
                    return;
                }
            }

            // Reset the anchorId for an anchoring serializer
            if (useAnchors && contentHandler instanceof IAnchoringSerializer) {
                IAnchoringSerializer as = (IAnchoringSerializer)contentHandler;
                as.stopAnchoring();
            }

            // Obtain the channel description
            IUserLayoutChannelDescription channelDesc = null;
            IUserLayoutNodeDescription parentNode = null;
            try {
                final IUserLayoutManager userLayoutManager = userPreferencesManager.getUserLayoutManager();
                channelDesc = (IUserLayoutChannelDescription) userLayoutManager.getNode(channelSubscribeId);
               
                final String parentNodeId = userLayoutManager.getParentId(channelDesc.getId());
                if (parentNodeId != null) {
                    parentNode = userLayoutManager.getNode(parentNodeId);
                }
            }
            catch (PortalException pe) {
                log.warn("Failed to load IUserLayoutChannelDescription and parent IUserLayoutNodeDescription for channel with subscribe id: " + channelSubscribeId, pe);
            }

            // Tell the StatsRecorder that this channel has rendered
            final IPerson person = userPreferencesManager.getPerson();
            final UserProfile userProfile = userPreferencesManager.getCurrentProfile();
            final long renderTime = cr.getRenderTime();
            final boolean renderedFromCache = cr.isRenderedFromCache();
           
            final ChannelRenderedInLayoutPortalEvent channelRenderedEvent = new ChannelRenderedInLayoutPortalEvent(this, person, userProfile, channelDesc, parentNode, renderTime, renderedFromCache);
            EventPublisherLocator.getApplicationEventPublisher().publishEvent(channelRenderedEvent);
        } else {
            handleRenderingError(request, response, channelSubscribeId,contentHandler,null,renderingStatus,"unsuccessful rendering","unsuccessful rendering",false);
            return;
        }
    }

    /**
     * Handles rendering output errors by replacing a channel instance with that of an error channel.
     * (or giving up if the error channel is failing as well)
     *
     * @param channelSubscribeId a <code>String</code> value
     * @param contentHandler a <code>ContentHandler</code> value
     * @param t a <code>Throwable</code> value
     * @param renderingStatus an <code>int</code> value
     * @param commonMessage a <code>String</code> value
     * @param technicalMessage a <code>String</code> value
     * @param partialOutput a <code>boolean</code> value
     */
    private void handleRenderingError(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId,ContentHandler contentHandler, Throwable t, int renderingStatus, String commonMessage, String technicalMessage,boolean partialOutput) {
        try {
            if (repeatRenderings.contains(channelSubscribeId)) {
                // this means that the error channel has failed :(
                String message="Unable to handle a rendering error through error channel.";
                if(t!=null) {
                    if(t instanceof InternalPortalException) {
                        InternalPortalException ipe=(InternalPortalException) t;
                        Throwable e=ipe.getCause();
                        message=message+" Error channel (channelSubscribeId='"+channelSubscribeId+"') has thrown the following exception: "+e.toString()+" Partial output possible !";
                        log.fatal("CError threw exception. Please fix CError immediately!", e);
                    } else {
                        message=message+" An following exception encountered while trying to render the error channel for channelSubscribeId='"+channelSubscribeId+"': "+t.toString();
                        log.fatal("CError threw exception. Please fix CError immediately!", t);
                    }
                } else {
                    // check status
                    message=message+" channelRenderingStatus=";

                    switch( renderingStatus )
                    {
                        case IChannelRenderer.RENDERING_SUCCESSFUL:
                            message += "successful";
                            break;
                        case IChannelRenderer.RENDERING_FAILED:
                            message += "failed";
                            break;
                        case IChannelRenderer.RENDERING_TIMED_OUT:
                            message += "timed out";
                            break;
                        default:
                            message += "UNKNOWN CODE: " + renderingStatus;
                            break;
                    }
                }
                message=message+" "+technicalMessage;
                log.error(message);
            } else {
                // first check for an exception
                if(t!=null ){
                    if(t instanceof InternalPortalException) {
                        InternalPortalException ipe=(InternalPortalException) t;
                        Throwable channelException=ipe.getCause();
                        replaceWithErrorChannel(request, response, channelSubscribeId, ErrorCode.RENDER_TIME_EXCEPTION,channelException,technicalMessage,true);
                    } else {
                        replaceWithErrorChannel(request, response, channelSubscribeId, ErrorCode.RENDER_TIME_EXCEPTION, t, technicalMessage, true);
                    }
                } else {
                    if(renderingStatus==IChannelRenderer.RENDERING_TIMED_OUT) {
                        replaceWithErrorChannel(request, response, channelSubscribeId,ErrorCode.TIMEOUT_EXCEPTION,t,technicalMessage,true);
                    } else {
                        replaceWithErrorChannel(request, response, channelSubscribeId,ErrorCode.GENERAL_ERROR,t,technicalMessage,true);
                    }
                }

                // remove channel renderer
                rendererTable.remove(channelSubscribeId);
                // re-try render
                if(!partialOutput) {
                    repeatRenderings.add(channelSubscribeId);
                    outputChannel(request, response, channelSubscribeId, contentHandler);
                }
            }
        } finally {
            // Set the subscribeId as the achorId for an anchoring serializer
            if (useAnchors && contentHandler instanceof IAnchoringSerializer) {
                IAnchoringSerializer as = (IAnchoringSerializer)contentHandler;
                as.stopAnchoring();
            }
        }
    }

    /**
     * A helper method to replace all occurences of a given channel instance
     * with that of an error channel.
     *
     * @param channelSubscribeId a <code>String</code> value
     * @param errorCode an ErrorCode
     * @param t a <code>Throwable</code> an exception that caused the problem
     * @param message a <code>String</code> an optional message to pass to the error channel
     * @param setRuntimeData a <code>boolean</code> wether the method should also set the ChannelRuntimeData for the newly instantiated error channel
     * @return an <code>IChannel</code> value of an error channel instance
     */
    private IChannel replaceWithErrorChannel(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId, ErrorCode errorCode, Throwable t, String message, boolean setRuntimeData) {
        // get and delete old channel instance
        IChannel oldInstance=channelTable.get(channelSubscribeId);
        if (log.isWarnEnabled())
            log.warn("Replacing channel [" + oldInstance
                + "], which had subscribeId [" + channelSubscribeId
                + "] with error channel because of error code "
                + errorCode + " message: " + message + " and throwable [" + t +"]",t);

        channelTable.remove(channelSubscribeId);
        rendererTable.remove(channelSubscribeId);

        CError errorChannel =
            new CError(errorCode,t,channelSubscribeId,oldInstance,message);
        if(setRuntimeData) {
            ChannelRuntimeData rd=new ChannelRuntimeData();
            rd.setBrowserInfo(browserInfo);
            if (localeManager != null)  {
                rd.setLocales(localeManager.getLocales());
            }
           
            final PortalControlStructures pcs = this.getPortalControlStructuresForChannel(request, response, channelSubscribeId);
           
      rd.setRemoteAddress(pcs.getHttpServletRequest().getRemoteAddr());
            rd.setHttpRequestMethod(pcs.getHttpServletRequest().getMethod());
            UPFileSpec up=new UPFileSpec(uPElement);
            up.setTargetNodeId(channelSubscribeId);
            rd.setUPFile(up);
            try {
                errorChannel.setRuntimeData(rd);
                errorChannel.setPortalControlStructures(pcs);
            } catch (Throwable e) {

                log.error("Encountered an exception while trying to set runtime data or portal control structures on the error channel!", e);
            }
        }
        channelTable.put(channelSubscribeId,errorChannel);
        return errorChannel;
    }

    /**
     * A helper method to replace all occurences of a secure channel instance
     * with that of a secure information channel.
     *
     * @param channelSubscribeId a <code>String</code> value
     * @param setRuntimeData a <code>boolean</code> wether the method should also set the ChannelRuntimeData for the newly instantiated secure info channel
     * @return an <code>IChannel</code> value of a secure info channel instance
     */
    private IChannel replaceWithSecureInfoChannel(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId, boolean setRuntimeData) {
        // get and delete old channel instance
        IChannel oldInstance=channelTable.get(channelSubscribeId);
        channelTable.remove(channelSubscribeId);
        rendererTable.remove(channelSubscribeId);

        CSecureInfo secureInfoChannel=new CSecureInfo(channelSubscribeId,oldInstance);
        if(setRuntimeData) {
            ChannelRuntimeData rd=new ChannelRuntimeData();
            rd.setBrowserInfo(browserInfo);
            if (localeManager != null)  {
                rd.setLocales(localeManager.getLocales());
            }
           
            final PortalControlStructures pcs = this.getPortalControlStructuresForChannel(request, response, channelSubscribeId);
           
            rd.setHttpRequestMethod(pcs.getHttpServletRequest().getMethod());
            rd.setRemoteAddress(pcs.getHttpServletRequest().getRemoteAddr());
            UPFileSpec up=new UPFileSpec(uPElement);
            up.setTargetNodeId(channelSubscribeId);
            rd.setUPFile(up);
            try {
                secureInfoChannel.setRuntimeData(rd);
                secureInfoChannel.setPortalControlStructures(pcs);
            } catch (Throwable e) {
                log.error("Encountered an exception while trying to set runtime data or portal control structures on the secure info channel!", e);
            }
        }
        channelTable.put(channelSubscribeId,secureInfoChannel);
        return secureInfoChannel;
    }


    /**
     * Instantiates a channel given just the channel subscribe Id.
     *
     * @param channelSubscribeId a channel instance Id in the userLayout
     * @return an <code>IChannel</code> object
     */
    public IChannel instantiateChannel(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId) throws PortalException {
        if (channelTable.get(channelSubscribeId) != null) {
            // reinstantiation
            channelTable.remove(channelSubscribeId);
        }
       
        // get channel information from the user layout manager
        final IUserLayoutManager userLayoutManager = userPreferencesManager.getUserLayoutManager();
        final IUserLayoutChannelDescription channel = (IUserLayoutChannelDescription) userLayoutManager.getNode(channelSubscribeId);
        if (channel != null) {
            return this.instantiateChannel(request, response, channel);
        }

        return null;
    }

    private IChannel instantiateChannel(HttpServletRequest request, HttpServletResponse response, IUserLayoutChannelDescription channelDescription) throws PortalException {
        final String channelSubscribeId = channelDescription.getChannelSubscribeId();
        final String channelPublishId = channelDescription.getChannelPublishId();
        // check if the user has permissions to instantiate this channel

        final IChannel channel;
        if(authorizationPrincipal.canRender(Integer.parseInt(channelPublishId))) {
      if (request == null) {
                channel = new CError(ErrorCode.GENERAL_ERROR, "Unable to get SessionId. No HttpServletRequest provided.", channelSubscribeId, null);
            }
            else {
                final HttpSession session = request.getSession();
                final String sessionId = session.getId();
                channel = ChannelFactory.instantiateLayoutChannel(channelDescription, sessionId);

                if (channel == null) {
                    throw new IllegalStateException("ChannelFactory returned null on request to instantiate layout channel with id [" + sessionId + "] and description [" + channelDescription + "]");
                }

                final IPerson person = userPreferencesManager.getPerson();
               
                final ApplicationEventPublisher applicationEventPublisher = EventPublisherLocator.getApplicationEventPublisher();
                final UserProfile currentProfile = userPreferencesManager.getCurrentProfile();
               
                IUserLayoutNodeDescription parentNode = null;
                try {
                    final IUserLayoutManager userLayoutManager = userPreferencesManager.getUserLayoutManager();
                   
                    final String parentNodeId = userLayoutManager.getParentId(channelDescription.getId());
                    if (parentNodeId != null) {
                        parentNode = userLayoutManager.getNode(parentNodeId);
                    }
                }
                catch (PortalException pe) {
                    log.warn("Failed to load parent IUserLayoutNodeDescription for channel with subscribe id: " + channelDescription.getChannelPublishId(), pe);
                }
                applicationEventPublisher.publishEvent(new ChannelInstanciatedInLayoutPortalEvent(this, person, currentProfile, channelDescription, parentNode));

                // Create and stuff the channel static data
                final ChannelStaticData channelStaticData = new ChannelStaticData(channelDescription.getParameterMap(), userPreferencesManager.getUserLayoutManager());
                channelStaticData.setChannelSubscribeId(channelSubscribeId);
                channelStaticData.setTimeout(channelDescription.getTimeout());
                channelStaticData.setPerson(person);
                channelStaticData.setJNDIContext(channelContext);
                channelStaticData.setICCRegistry(new ICCRegistry(this, channelSubscribeId));
                channelStaticData.setChannelPublishId(channelDescription.getChannelPublishId());
                channelStaticData.setSerializerName(serializerName);
                channelStaticData.setWebApplicationContext(PortalApplicationContextLocator.getRequiredWebApplicationContext());

                if (channel instanceof IPrivileged) {
                    this.feedPortalControlStructuresToChannel(request, response, channelSubscribeId, (IPrivileged)channel);
                }

                channel.setStaticData(channelStaticData);
            }
        }
        else {
            // user is not authorized to instantiate this channel
            // create an instance of an error channel instead
            channel = new CError(ErrorCode.CHANNEL_AUTHORIZATION_EXCEPTION, "You don't have authorization to render this channel.", channelSubscribeId, null);
        }

        this.channelTable.put(channelSubscribeId, channel);
        return channel;
    }


    /**
     * Passes a layout-level event to a channel.
     * @param channelSubscribeId the channel subscribe id
     * @param le the portal event
     */
    public void passPortalEvent(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId, PortalEvent le) {
        IChannel ch = this.getChannelInstance(request, response, channelSubscribeId);

        try {
            if (ch instanceof IPrivileged) {
                final PortalControlStructures pcs = this.getPortalControlStructuresForChannel(request, response, channelSubscribeId);
                ((IPrivileged)ch).setPortalControlStructures(pcs);
            }
           
            ch.receiveEvent(le);
        }
        catch (Exception e) {
            log.error("Error sending layout event " + le + " to channel " + ch, e);
        }
    }


    /**
     * Determine target channel and pass corresponding
     * actions/params to that channel
     * @param request the <code>HttpServletRequest</code>
     */
    private void processRequestChannelParameters(HttpServletRequest request, HttpServletResponse response) {
        final IChannelRequestParameterManager channelParameterManager = ChannelRequestParameterManagerLocator.getChannelRequestParameterManager();
       
        final Set<String> targetedChannelIds = channelParameterManager.getTargetedChannelIds(request);
        if (targetedChannelIds.size() > 0) {
            this.channelTarget = targetedChannelIds.iterator().next();
        }
        else {
            this.channelTarget = null;
        }

        if (channelTarget != null) {
            // Obtain the channel description
            IUserLayoutChannelDescription channelDesc = null;
            IUserLayoutNodeDescription parentNode = null;
            try {
                final IUserLayoutManager userLayoutManager = userPreferencesManager.getUserLayoutManager();
                channelDesc = (IUserLayoutChannelDescription) userLayoutManager.getNode(channelTarget);
               
                final String parentNodeId = userLayoutManager.getParentId(channelDesc.getId());
                if (parentNodeId != null) {
                    parentNode = userLayoutManager.getNode(parentNodeId);
                }
            }
            catch (PortalException pe) {
                log.warn("Failed to load IUserLayoutChannelDescription and parent IUserLayoutNodeDescription for channel with subscribe id: " + channelTarget, pe);
            }

            final IPerson person = userPreferencesManager.getPerson();
           
            // Tell StatsRecorder that a user has interacted with the channel
            if (channelDesc != null) {
                final ApplicationEventPublisher applicationEventPublisher = EventPublisherLocator.getApplicationEventPublisher();
                final UserProfile currentProfile = userPreferencesManager.getCurrentProfile();
                applicationEventPublisher.publishEvent(new ChannelTargetedInLayoutPortalEvent(this, person, currentProfile, channelDesc, parentNode));
            }

           
            final Map<String, Object[]> channelParameters = channelParameterManager.getChannelParameters(request, channelTarget);
            if (channelParameters != null) {
                targetParams = new HashMap<String, Object>(channelParameters);
            }
            else {
                targetParams = null;
            }
           
            if(channelParameters != null && channelParameters.size() > 0) {
                // only do grouped rendering if there are some parameters passed
                // to the target channel.
                // detect if channel target talks to other channels
                groupedRendering = hasListeningChannels(channelTarget);
            }

            IChannel channel;
            if ((channel=channelTable.get(channelTarget)) == null) {
                try {
                    channel=instantiateChannel(request, response, channelTarget);
                } catch (Throwable e) {
          if (person.isGuest() == true)
          {
            // We get this alot when people's sessions have timed out and they get directed
            // to the guest page. Changed to WARN because there might be a need to note this
            // to diagnose problems with the guest layout.

            log.warn("unable to pass find/create an instance of a channel. Bogus Id ? ! (id='"+channelTarget+"').");
          }else{
            log.error("unable to pass find/create an instance of a channel. Bogus Id ? ! (id='"+channelTarget+"' uid='"+person.getID()+"').",e);
          }
                    channel=replaceWithErrorChannel(request, response, channelTarget, ErrorCode.SET_STATIC_DATA_EXCEPTION, e, null, false);
                }
            }
        }
    }

    private IChannel feedPortalControlStructuresToChannel(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId, IPrivileged prvChanObj) {
        final PortalControlStructures pcs = this.getPortalControlStructuresForChannel(request, response, channelSubscribeId);
       
        try {
            prvChanObj.setPortalControlStructures(pcs);
        }
        catch (Exception e) {
            prvChanObj = (IPrivileged)replaceWithErrorChannel(request, response, channelSubscribeId, ErrorCode.SET_PCS_EXCEPTION, e, null, false);

            // set portal control structures
            try {
                prvChanObj.setPortalControlStructures(pcs);
            }
            catch (Exception e2) {
                // things are looking bad for our hero
                log.error("Error channel threw exception accepting PortalControlStructures", e2);
            }
        }
       
        return (IChannel)prvChanObj;
    }

    /**
     * Obtain an instance of a channel.
     *
     * @param channelSubscribeId a <code>String</code> value
     * @return an <code>IChannel</code> object
     */
    public IChannel getChannelInstance(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId) {
        IChannel ch = channelTable.get(channelSubscribeId);
        if (ch == null) {
            try {
                ch = instantiateChannel(request, response, channelSubscribeId);
            }
            catch (Throwable e) {
                log.warn(e, e);
                return null;
            }
        }
        return ch;
    }


    /**
     * Removes channel instance from the internal caches.
     *
     * @param channelSubscribeId a <code>String</code> value
     */
    public void removeChannel(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId) {
        IChannel ch=channelTable.get(channelSubscribeId);
        if(ch!=null) {
            channelCacheTable.remove(ch);
           
            this.passPortalEvent(request, response, channelSubscribeId, PortalEvent.UNSUBSCRIBE_EVENT);
           
            channelTable.remove(channelSubscribeId);
           
            if (log.isDebugEnabled()) {
                log.debug("removed channel with subscribe id="+channelSubscribeId);
            }
        }
    }

    /**
     * Signals the start of a new rendering cycle.
     *
     * @param request a <code>HttpServletRequest</code> value
     * @param response a <code>HttpServletResponse</code> value
     * @param uPElement an <code>UPFileSpec</code> value
     */
    public void startRenderingCycle(HttpServletRequest request, HttpServletResponse response, UPFileSpec uPElement) {
        this.browserInfo = new BrowserInfo(request);
        this.uPElement = uPElement;
        this.rendererTable.clear();

        processRequestChannelParameters(request, response);
    }

    /**
     * Specifies if this particular rendering cycle is using
     * character caching.
     *
     * @return a <code>boolean</code> value
     */
    public boolean isCharacterCaching() {
        return this.characterCaching;
    }

    /**
     * Specify that the current rendering cycle should be
     * using (or not) character caching.
     *
     * @param setting a <code>boolean</code> value
     */
    public void setCharacterCaching(boolean setting) {
        this.characterCaching=setting;
    }

    /**
     * Specify <code>UPFileSpec</code> object that will be
     * used to construct file portion of the context path
     * in the auto-generated URLs, also known as the baseActionURL.
     *
     * @param uPElement an <code>UPFileSpec</code> value
     */
    public void setUPElement(UPFileSpec uPElement) {
        this.uPElement = uPElement;
    }

    public boolean doChannelAction(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId, boolean noTimeout) throws PortalException {
        // see if the channel has already been instantiated
        // see if the channel is cached
        IUserLayoutNodeDescription node = userPreferencesManager.getUserLayoutManager().getNode(channelSubscribeId);
        if (!(node instanceof IUserLayoutChannelDescription)) {
            throw new PortalException("'" + channelSubscribeId + "' is not a channel node !");
        }

        final IUserLayoutChannelDescription channel = (IUserLayoutChannelDescription) node;
        final long timeOut = channel.getTimeout();

        IChannel ch = channelTable.get(channelSubscribeId);
        final IChannel originalChannel = ch;

        if (ch == null || ch instanceof CSecureInfo) {
            try {
                ch = instantiateChannel(request, response, channel);
            }
            catch (Throwable e) {
                ch = replaceWithErrorChannel(request, response, channelSubscribeId, ErrorCode.SET_STATIC_DATA_EXCEPTION, e, null, false);
            }
        }
       
        if (ch instanceof IPrivileged) {
            ch = this.feedPortalControlStructuresToChannel(request, response, channelSubscribeId, (IPrivileged) ch);
        }
       
        //If the channel object has changed (likely now an error channel) return immediatly
        if (originalChannel != null && originalChannel != ch) {
            return false;
        }
       
        final ChannelRuntimeData runtimeData = this.getChannelRuntimeData(request, channelSubscribeId, RequestType.ACTION);

        // Build a new channel renderer instance.
        final IChannelRenderer channelRenderer = cChannelRendererFactory.newInstance(ch, runtimeData);

        if (noTimeout) {
            channelRenderer.setTimeout(0);
        }
        else {
            channelRenderer.setTimeout(timeOut);
        }

        channelRenderer.startRendering();
       
        final int renderingStatus;
        try {
            renderingStatus = channelRenderer.completeRendering();
        }
        catch (Throwable t) {
            ch = replaceWithErrorChannel(request, response, channelSubscribeId, ErrorCode.RENDER_TIME_EXCEPTION, t, null, false);
            log.error("Failed to complete action", t);
            return false;
        }

        if (renderingStatus != IChannelRenderer.RENDERING_SUCCESSFUL) {
            final ErrorCode errorCode;
            if (renderingStatus == IChannelRenderer.RENDERING_TIMED_OUT) {
                errorCode = ErrorCode.TIMEOUT_EXCEPTION;
            }
            else {
                errorCode = ErrorCode.GENERAL_ERROR;
            }
           
            ch = replaceWithErrorChannel(request, response, channelSubscribeId, errorCode, null, "unsuccessful rendering", true);
            log.error("Action did not compplete successefully: " + renderingStatus);
            return false;
        }
       
        // Obtain the channel description
        IUserLayoutChannelDescription channelDesc = null;
        IUserLayoutNodeDescription parentNode = null;
        try {
            final IUserLayoutManager userLayoutManager = userPreferencesManager.getUserLayoutManager();
            channelDesc = (IUserLayoutChannelDescription) userLayoutManager.getNode(channelSubscribeId);
           
            final String parentNodeId = userLayoutManager.getParentId(channelDesc.getId());
            if (parentNodeId != null) {
                parentNode = userLayoutManager.getNode(parentNodeId);
            }
        }
        catch (PortalException pe) {
            log.warn("Failed to load IUserLayoutChannelDescription and parent IUserLayoutNodeDescription for channel with subscribe id: " + channelSubscribeId, pe);
        }
       
        // Tell the StatsRecorder that this channel has rendered
        final IPerson person = userPreferencesManager.getPerson();
        final UserProfile userProfile = userPreferencesManager.getCurrentProfile();
        final long renderTime = channelRenderer.getRenderTime();
       
        final PortletActionInLayoutPortalEvent portletActionEvent = new PortletActionInLayoutPortalEvent(this, person, userProfile, channel, parentNode, renderTime);
        EventPublisherLocator.getApplicationEventPublisher().publishEvent(portletActionEvent);
       
        return true;
    }
       
    /**
     * Initiate channel rendering cycle.
     *
     * @param channelSubscribeId a <code>String</code> value
     * @return a <code>IChannelRenderer</code> value
     * @exception PortalException if an error occurs
     */
    public IChannelRenderer startChannelRendering(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId) throws PortalException {
        return startChannelRendering(request, response, channelSubscribeId, false);
    }

    /**
     * Initiate channel rendering cycle, possibly disabling timeout.
     *
     * @param channelSubscribeId a <code>String</code> value
     * @param noTimeout a <code>boolean</code> value specifying if the
     *                  time out rendering control should be disabled.
     * @return a <code>IChannelRenderer</code> value
     * @exception PortalException if an error occurs
     */
    private IChannelRenderer startChannelRendering(HttpServletRequest request, HttpServletResponse response, String channelSubscribeId, boolean noTimeout) throws PortalException {
        // see if the channel has already been instantiated
        // see if the channel is cached
        IChannel ch;
        long timeOut=0;

        IUserLayoutNodeDescription node=userPreferencesManager.getUserLayoutManager().getNode(channelSubscribeId);
        if(!(node instanceof IUserLayoutChannelDescription)) {
            throw new PortalException("'"+channelSubscribeId+"' is not a channel node !");
        }

        IUserLayoutChannelDescription channel=(IUserLayoutChannelDescription) node;
        timeOut=channel.getTimeout();

        ch = channelTable.get(channelSubscribeId);

        // replace channels that are specified as needing to be
        // rendered securely with CSecureInfo.
        if (!request.isSecure() && channel.isSecure()){
            if (!(ch instanceof CSecureInfo)){
                ch = replaceWithSecureInfoChannel(request, response, channelSubscribeId, false);
            }
        }
        else{
            // A secure channel may not have been able to render at one
            // time but now it can, create its instance to replace the
            // cached CSecureInfo entry.
            if (ch == null || ch instanceof CSecureInfo) {
                try {
                    ch = instantiateChannel(request, response, channel);
                }
                catch (Throwable e) {
                    ch = replaceWithErrorChannel(request, response, channelSubscribeId, ErrorCode.SET_STATIC_DATA_EXCEPTION, e, null, false);
                }
            }
        }

        if (ch instanceof IPrivileged) {
            this.feedPortalControlStructuresToChannel(request, response, channelSubscribeId, (IPrivileged) ch);
        }
       
        final ChannelRuntimeData runtimeData;
        if(!channelSubscribeId.equals(channelTarget)) {
            runtimeData = this.getChannelRuntimeData(request, channelSubscribeId, RequestType.RENDER);
        }
        else {
            // set up runtime data that will be passed to the IChannelRenderer
            runtimeData = this.getChannelRuntimeData(request, this.channelTarget, RequestType.RENDER);
        }

        // Build a new channel renderer instance.
        final IChannelRenderer channelRenderer = cChannelRendererFactory.newInstance(ch, runtimeData);

        channelRenderer.setCharacterCacheable(this.characterCaching);
        if(ch instanceof ICacheable) {
            channelRenderer.setCacheTables(this.channelCacheTable);
        }

        if (noTimeout) {
            channelRenderer.setTimeout(0);
        }
        else {
            channelRenderer.setTimeout(timeOut);
        }

        if (groupedRendering && (isListeningToChannels(channelSubscribeId) || channelSubscribeId.equals(channelTarget))) {
            // channel might depend on the target channel
            pendingChannels.add(channelSubscribeId); // defer rendering start
        }
        else {
            channelRenderer.startRendering();
        }
        rendererTable.put(channelSubscribeId, channelRenderer);

        return channelRenderer;
    }

    /**
     * Builds ChannelRuntimeData from a request, sets the parameters, query string
     * browser info, locale manager, method, remote address, and UPFileSpec
     */
    private ChannelRuntimeData getChannelRuntimeData(HttpServletRequest request, String channelSubscribeId, RequestType requestType) {
        final ChannelRuntimeData runtimeData = new ChannelRuntimeData();
       
        if (channelSubscribeId.equals(this.channelTarget) || RequestType.ACTION.equals(requestType)) {
            if (this.targetParams != null) {
                runtimeData.setParameters(this.targetParams);
            }
           
            final String queryString = request.getQueryString();
            if (queryString != null && queryString.indexOf("=") == -1) {
                runtimeData.setKeywords(queryString);
            }
           
            if (log.isDebugEnabled()) {
                log.debug("Marking channel " + channelSubscribeId + " as targeted. targetedId=" + this.channelTarget + ", requestType=" + requestType);
            }
           
            runtimeData.setTargeted(true);
        }
       
        runtimeData.setBrowserInfo(this.browserInfo);
       
        if (this.localeManager != null)  {
            runtimeData.setLocales(this.localeManager.getLocales());
        }
        runtimeData.setHttpRequestMethod(request.getMethod());
        runtimeData.setRemoteAddress(request.getRemoteAddr());

        final UPFileSpec upFile = new UPFileSpec(this.uPElement);
        upFile.setTargetNodeId(channelSubscribeId);
        runtimeData.setUPFile(upFile);
       
        final UserPreferences userPreferences = this.userPreferencesManager.getUserPreferences();
        final StructureStylesheetUserPreferences structureStylesheetUserPreferences = userPreferences.getStructureStylesheetUserPreferences();
        final String userLayoutRoot = structureStylesheetUserPreferences.getParameterValue("userLayoutRoot");
        if (userLayoutRoot != null && !IUserLayout.ROOT_NODE_NAME.equals(userLayoutRoot)) {
            runtimeData.setRenderingAsRoot(true);
        }
       
        runtimeData.setRequestType(requestType);
       
        return runtimeData;
    }

    synchronized void registerChannelDependency(String listenerChannelSubscribeId, String talkerChannelSubscribeId) {
        Set<String> talkers=iccListeners.get(listenerChannelSubscribeId);
        if(talkers==null) {
            talkers=new HashSet<String>();
            iccListeners.put(listenerChannelSubscribeId,talkers);
        }
        talkers.add(talkerChannelSubscribeId);

        Set<String> listeners=iccTalkers.get(talkerChannelSubscribeId);
        if(listeners==null) {
            listeners=new HashSet<String>();
            iccTalkers.put(talkerChannelSubscribeId,listeners);
        }
        listeners.add(listenerChannelSubscribeId);
    }


    private Set<String> getListeningChannels(String talkerChannelSubscribeId) {
        return iccTalkers.get(talkerChannelSubscribeId);
    }

    private boolean isListeningToChannels(String listenerChannelSubscribeId) {
        return (iccListeners.get(listenerChannelSubscribeId)!=null);
    }

    private boolean hasListeningChannels(String talkerChannelSubscribeId) {
        return (iccTalkers.get(talkerChannelSubscribeId)!=null);
    }

    synchronized void removeChannelDependency(String listenerChannelSubscribeId, String talkerChannelSubscribeId) {
        Set<String> talkers=iccListeners.get(listenerChannelSubscribeId);
        if(talkers!=null) {
            talkers.remove(talkerChannelSubscribeId);
            if(talkers.isEmpty()) {
                iccListeners.remove(listenerChannelSubscribeId);
            }
        }

        Set<String> listeners=iccTalkers.get(talkerChannelSubscribeId);
        if(listeners!=null) {
            listeners.remove(listenerChannelSubscribeId);
            if(listeners.isEmpty()) {
                iccTalkers.remove(talkerChannelSubscribeId);
            }
        }
    }

    public String getChannelTarget() {
        return channelTarget;
    }

    // LayoutEventListener interface implementation
    public void channelAdded(LayoutEvent ev) {}
    public void channelUpdated(LayoutEvent ev) {}
    public void channelMoved(LayoutMoveEvent ev) {}
    public void channelDeleted(LayoutMoveEvent ev) {
        //No way to have the request/response passed to use. Use the holder instead
        final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        final HttpServletRequest request;
        if (requestAttributes instanceof ServletRequestAttributes) {
            request = ((ServletRequestAttributes)requestAttributes).getRequest();
        }
        else {
            log.warn("Available RequestAttributes='" + requestAttributes + "' do not implement ServletRequestAttributes");
            request = null;
        }
       
        final IUserLayoutNodeDescription nodeDescription = ev.getNodeDescription();
        this.removeChannel(request, null, nodeDescription.getId());
    }

    public void folderAdded(LayoutEvent ev) {}
    public void folderUpdated(LayoutEvent ev) {}
    public void folderMoved(LayoutMoveEvent ev) {}
    public void folderDeleted(LayoutMoveEvent ev) {}

    public void layoutLoaded() {}
    public void layoutSaved() {}

    public void setLocaleManager(LocaleManager lm) {
        this.localeManager = lm;
    }

  /**
   * Get the dynamic channel title for a given channelSubscribeID.
   * Returns null if no dynamic channel (the rendering infrastructure
   * calling this method should fall back on a default title when this
   * method returns null).
   * @since uPortal 2.5.1
   * @param channelSubscribeId
   * @throws IllegalArgumentException if channelSubcribeId is null
   * @throws IllegalStateException if
   */
  public String getChannelTitle(String channelSubscribeId) {

    if (log.isTraceEnabled()) {
      log.trace("ChannelManager getting dynamic title for channel with subscribe id=" + channelSubscribeId);
    }

    // obtain IChannelRenderer
    IChannelRenderer channelRenderer = rendererTable.get(channelSubscribeId);
   
    if (log.isDebugEnabled()) {
        log.debug("Getting Title - Retrieved channel renderer " + (channelRenderer != null ? channelRenderer.toString() : null) + " for subscribe id: " + channelSubscribeId);
    }

        // default to null (no dynamic channel title.
        String channelTitle = null;

        // dynamic channel title support is not in IChannelRenderer itself because
        // that would have required a change to the IChannelRenderer interface
        if (channelRenderer instanceof IDynamicChannelTitleRenderer ) {

            final IDynamicChannelTitleRenderer channelTitleRenderer = (IDynamicChannelTitleRenderer) channelRenderer;
            channelTitle = channelTitleRenderer.getChannelTitle();

            if (log.isDebugEnabled()) {
              log.debug("Dynamic title for channel with subscribe id=" + channelSubscribeId + " is [" + channelTitle + "].");
            }
        }

        return channelTitle;

  }

    public String getSubscribeId(String fname) throws PortalException
    {
        IUserLayoutManager ulm = userPreferencesManager.getUserLayoutManager();
        return ulm.getSubscribeId(fname);
    }
   
    /**
     * Sets the serializer name.
     * @return serializerName
     */
    public String getSerializerName() {
        return serializerName;
    }
   
    /**
     * Setter method for the serializer name.
     * @param serializerName
     */
    public void setSerializerName(String serializerName) {
        this.serializerName = serializerName;
    }
}
TOP

Related Classes of org.jasig.portal.ChannelManager

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.