protected PortletWindowData getOrCreateDefaultPortletWindowData(
      HttpServletRequest request,
      IPortletEntityId portletEntityId,
      IPortletWindowId portletWindowId,
      IPortletWindowId delegationParentId) {
    // Sync on session map to make sure duplicate PortletWindowData is never created
    final PortletWindowCache<PortletWindowData> portletWindowDataMap =
        getPortletWindowDataMap(request);
    // Check if there portlet window data cached in the session
    PortletWindowData portletWindowData = portletWindowDataMap.getWindow(portletWindowId);
    if (portletWindowData != null) {
      logger.trace(
          "Found PortletWindowData {} in session cache", portletWindowData.getPortletWindowId());
      return portletWindowData;
    }

    // Create new window data for and initialize
    portletWindowData = new PortletWindowData(portletWindowId, portletEntityId, delegationParentId);
    this.initializePortletWindowData(request, portletWindowData);

    // Store in the session cache
    portletWindowData = portletWindowDataMap.storeIfAbsentWindow(portletWindowData);
    logger.trace(
        "Created PortletWindowData {} and stored session cache, wrapping as IPortletWindow and returning",
        portletWindowData.getPortletWindowId());

    return portletWindowData;
  }
  /**
   * @param request
   * @param portletEntityId
   * @param portletWindows
   * @param portletWindowMap
   * @param portletWindowDataMap
   */
  protected void addPortletWindowData(
      HttpServletRequest request,
      IPortletEntityId portletEntityId,
      final Set<IPortletWindow> portletWindows,
      final PortletWindowCache<IPortletWindow> portletWindowMap,
      final PortletWindowCache<PortletWindowData> portletWindowDataMap) {

    final Set<PortletWindowData> windows = portletWindowDataMap.getWindows(portletEntityId);
    if (windows == null) {
      return;
    }

    for (final PortletWindowData portletWindowData : windows) {
      final IPortletWindowId portletWindowId = portletWindowData.getPortletWindowId();

      // Skip data windows that aren't for this entity and for windows that are already in the
      // request cache
      if (!portletEntityId.equals(portletWindowData.getPortletEntityId())
          || portletWindowMap.containsWindow(portletWindowId)) {
        continue;
      }

      // Wrap the data in a window and stick it in the request cache
      IPortletWindow portletWindow = this.wrapPortletWindowData(request, portletWindowData);
      portletWindow = portletWindowMap.storeIfAbsentWindow(portletWindow);

      portletWindows.add(portletWindow);
    }
  }
  @Override
  public IPortletWindow createDelegatePortletWindow(
      HttpServletRequest request,
      IPortletEntityId portletEntityId,
      IPortletWindowId delegationParentId) {
    Validate.notNull(request, "request can not be null");
    Validate.notNull(portletEntityId, "portletEntityId can not be null");

    // TODO does a delegate portlet entity need some sort of special treatment or do we just assume
    // that the calling code is using one?

    final IPortletWindowId portletWindowId =
        this.getDefaultPortletWindowId(request, portletEntityId);

    final PortletWindowCache<IPortletWindow> portletWindowMap = getPortletWindowMap(request);

    // Check if there is portlet window cached in the request
    IPortletWindow portletWindow = portletWindowMap.getWindow(portletWindowId);
    if (portletWindow != null) {
      logger.trace("Found IPortletWindow {} in request cache", portletWindow.getPortletWindowId());
      return portletWindow;
    }

    final PortletWindowData portletWindowData =
        this.getOrCreateDefaultPortletWindowData(
            request, portletEntityId, portletWindowId, delegationParentId);
    portletWindow = wrapPortletWindowData(request, portletWindowData);
    if (portletWindow == null) {
      return null;
    }

    // Cache the wrapped window in the request
    return portletWindowMap.storeIfAbsentWindow(portletWindow);
  }
  @Override
  public IPortletWindow getOrCreateDefaultPortletWindow(
      HttpServletRequest request, IPortletEntityId portletEntityId) {
    Validate.notNull(request, "request can not be null");
    Validate.notNull(portletEntityId, "portletEntityId can not be null");

    final IPortletWindowId portletWindowId =
        this.getDefaultPortletWindowId(request, portletEntityId);

    final PortletWindowCache<IPortletWindow> portletWindowMap = getPortletWindowMap(request);

    // Check if there is portlet window cached in the request
    IPortletWindow portletWindow = portletWindowMap.getWindow(portletWindowId);
    if (portletWindow != null) {
      logger.trace("Found IPortletWindow {} in request cache", portletWindow.getPortletWindowId());
      return portletWindow;
    }

    final PortletWindowData portletWindowData =
        this.getOrCreateDefaultPortletWindowData(request, portletEntityId, portletWindowId);
    portletWindow = wrapPortletWindowData(request, portletWindowData);
    if (portletWindow == null) {
      return null;
    }

    // Cache the wrapped window in the request
    return portletWindowMap.storeIfAbsentWindow(portletWindow);
  }
  protected PortletWindowData getPortletWindowData(
      HttpServletRequest request, IPortletWindowId portletWindowId) {
    final PortletWindowCache<PortletWindowData> portletWindowDataMap =
        getPortletWindowDataMap(request, false);
    if (portletWindowDataMap == null) {
      return null;
    }

    final PortletWindowData portletWindowData = portletWindowDataMap.getWindow(portletWindowId);
    if (portletWindowData == null) {
      logger.trace("No PortletWindowData {} in session cache", portletWindowId);
      return null;
    }

    logger.trace(
        "Found PortletWindowData {} in session cache", portletWindowData.getPortletWindowId());
    return portletWindowData;
  }
  /* (non-Javadoc)
   * @see org.jasig.portal.portlet.registry.IPortletWindowRegistry#getPortletWindow(javax.servlet.http.HttpServletRequest, org.jasig.portal.portlet.om.IPortletWindowId)
   */
  @Override
  public IPortletWindow getPortletWindow(
      HttpServletRequest request, IPortletWindowId portletWindowId) {
    Validate.notNull(request, "request can not be null");
    Validate.notNull(portletWindowId, "portletWindowId can not be null");

    final PortletWindowCache<IPortletWindow> portletWindowMap = getPortletWindowMap(request);

    IPortletWindow portletWindow = portletWindowMap.getWindow(portletWindowId);
    if (portletWindow != null) {
      logger.trace("Found IPortletWindow {} in request cache", portletWindow.getPortletWindowId());
      return portletWindow;
    }

    final PortletWindowIdImpl localPortletWindowId =
        this.convertPortletWindowId(request, portletWindowId);

    // Find the window data from the correct window data map
    final PortletWindowData portletWindowData;
    if (STATELESS_PORTLET_WINDOW_ID.equals(localPortletWindowId.getWindowInstanceId())) {
      final PortletWindowCache<PortletWindowData> statelessPortletWindowDataMap =
          this.getStatelessPortletWindowDataMap(request, false);
      if (statelessPortletWindowDataMap != null) {
        portletWindowData = statelessPortletWindowDataMap.getWindow(portletWindowId);
      } else {
        portletWindowData = null;
      }
    } else {
      portletWindowData = this.getPortletWindowData(request, portletWindowId);
    }

    if (portletWindowData == null) {
      logger.trace("No IPortletWindow {} exists, returning null");
      return null;
    }

    portletWindow = this.wrapPortletWindowData(request, portletWindowData);

    // Cache the wrapped window in the request
    return portletWindowMap.storeIfAbsentWindow(portletWindow);
  }
  @Override
  public Set<IPortletWindow> getAllPortletWindowsForEntity(
      HttpServletRequest request, IPortletEntityId portletEntityId) {
    Validate.notNull(request, "request can not be null");
    Validate.notNull(portletEntityId, "portletEntityId can not be null");

    final PortletWindowCache<IPortletWindow> portletWindowMap = getPortletWindowMap(request);
    final Set<IPortletWindow> portletWindows =
        new LinkedHashSet<IPortletWindow>(portletWindowMap.getWindows(portletEntityId));

    // Check for session cached windows that haven't been accessed in this request
    final PortletWindowCache<PortletWindowData> portletWindowDataMap =
        this.getPortletWindowDataMap(request);
    this.addPortletWindowData(
        request, portletEntityId, portletWindows, portletWindowMap, portletWindowDataMap);

    // Check for stateless windows that exist on this request
    final PortletWindowCache<PortletWindowData> statelessPortletWindowDataMap =
        this.getStatelessPortletWindowDataMap(request, false);
    if (statelessPortletWindowDataMap != null) {
      this.addPortletWindowData(
          request,
          portletEntityId,
          portletWindows,
          portletWindowMap,
          statelessPortletWindowDataMap);
    }

    // If there were no windows in the set create the default one for the entity
    if (portletWindows.isEmpty()) {
      final IPortletWindow portletWindow =
          this.getOrCreateDefaultPortletWindow(request, portletEntityId);
      portletWindows.add(portletWindow);
    }

    return portletWindows;
  }
  @Override
  public IPortletWindow getOrCreateStatelessPortletWindow(
      HttpServletRequest request, IPortletWindowId basePortletWindowId) {
    // Need the basePortletWindowId to be an instance of PortletWindowIdImpl so that we can extract
    // the entity ID
    if (!(basePortletWindowId instanceof PortletWindowIdImpl)) {
      final String basePortletWindowIdStr = basePortletWindowId.getStringId();
      basePortletWindowId = this.getPortletWindowId(request, basePortletWindowIdStr);
    }

    // Get the entity ID for the portlet window
    final IPortletEntityId portletEntityId =
        ((PortletWindowIdImpl) basePortletWindowId).getPortletEntityId();

    // Create the stateless ID
    final PortletWindowIdImpl statelessPortletWindowId =
        this.createPortletWindowId(STATELESS_PORTLET_WINDOW_ID, portletEntityId);

    // See if there is already a request cached stateless window
    IPortletWindow statelessPortletWindow =
        this.getPortletWindow(request, statelessPortletWindowId);
    if (statelessPortletWindow != null) {
      return statelessPortletWindow;
    }

    // Lookup the base portlet window to clone the stateless from
    final IPortletWindow basePortletWindow = this.getPortletWindow(request, basePortletWindowId);

    final PortletWindowCache<PortletWindowData> statelessPortletWindowDataMap =
        this.getStatelessPortletWindowDataMap(request, true);

    // If no base to clone from lookup the entity and pluto definition data
    if (basePortletWindow == null) {
      final IPortletEntity portletEntity =
          this.portletEntityRegistry.getPortletEntity(request, portletEntityId);
      if (portletEntity == null) {
        throw new IllegalArgumentException(
            "No IPortletEntity could be found for "
                + portletEntity
                + " while creating stateless portlet window for "
                + basePortletWindowId);
      }

      final IPortletDefinition portletDefinition = portletEntity.getPortletDefinition();
      final IPortletDefinitionId portletDefinitionId = portletDefinition.getPortletDefinitionId();
      final PortletDefinition portletDescriptor =
          this.portletDefinitionRegistry.getParentPortletDescriptor(portletDefinitionId);

      final PortletWindowData portletWindowData =
          new PortletWindowData(statelessPortletWindowId, portletEntityId);
      statelessPortletWindowDataMap.storeWindow(portletWindowData);

      statelessPortletWindow =
          new StatelessPortletWindowImpl(portletWindowData, portletEntity, portletDescriptor);
    }
    // Clone the existing base window
    else {
      final PortletWindowData portletWindowData =
          new PortletWindowData(statelessPortletWindowId, portletEntityId);
      portletWindowData.setExpirationCache(basePortletWindow.getExpirationCache());
      portletWindowData.setPortletMode(basePortletWindow.getPortletMode());
      portletWindowData.setWindowState(basePortletWindow.getWindowState());
      portletWindowData.setPublicRenderParameters(basePortletWindow.getPublicRenderParameters());
      portletWindowData.setRenderParameters(basePortletWindow.getRenderParameters());

      statelessPortletWindowDataMap.storeWindow(portletWindowData);

      final IPortletEntity portletEntity = basePortletWindow.getPortletEntity();
      final PortletDefinition portletDescriptor =
          basePortletWindow.getPlutoPortletWindow().getPortletDefinition();
      statelessPortletWindow =
          new StatelessPortletWindowImpl(portletWindowData, portletEntity, portletDescriptor);
    }

    // Cache the stateless window in the request
    final PortletWindowCache<IPortletWindow> portletWindowMap = this.getPortletWindowMap(request);
    portletWindowMap.storeWindow(statelessPortletWindow);

    return statelessPortletWindow;
  }