/*
* 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.jetspeed.om.window.impl;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.portlet.PortletMode;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.WindowState;
import org.apache.commons.collections.list.TreeList;
import org.apache.jetspeed.aggregator.PortletContent;
import org.apache.jetspeed.aggregator.RenderTrackable;
import org.apache.jetspeed.container.PortletWindow;
import org.apache.jetspeed.container.PortletWindowID;
import org.apache.jetspeed.factory.PortletInstance;
import org.apache.jetspeed.om.page.ContentFragment;
import org.apache.jetspeed.om.page.Fragment;
import org.apache.jetspeed.om.portlet.PortletDefinition;
import org.apache.jetspeed.portlet.HeadElement;
import org.apache.jetspeed.request.RequestContext;
import org.apache.jetspeed.util.HeadElementsUtils;
import org.apache.jetspeed.util.KeyValue;
import org.apache.pluto.container.PortletRequestContext;
import org.apache.pluto.container.PortletResponseContext;
/**
* <P>
* The <CODE>PortletWindow</CODE> implementation represents a single window
* of an portlet instance as it can be shown only once on a single page.
* Adding the same portlet e.g. twice on a page results in two different windows.
* </P>
*
* @author <a href="mailto:david@bluesunrise.com">David Sean Taylor</a>
* @version $Id: PortletWindowImpl.java 911881 2010-02-19 17:58:50Z rwatler $
**/
public class PortletWindowImpl implements PortletWindow, PortletWindowID, RenderTrackable
{
private static final long serialVersionUID = 6578938580906866201L;
private String id;
private String portletEntityId;
private ContentFragment fragment;
private Map<String, Object> attributes;
protected int timeoutCount = 0;
protected long expiration = 0;
private PortletDefinition pd;
private RequestContext requestContext;
// PortletWindow invocation state
private Action action;
private PortletRequest portletRequest;
private PortletResponseContext portletResponseContext;
private PortletRequestContext portletRequestContext;
private PortletResponse portletResponse;
private PortletInstance portletInstance;
private PortletMode portletMode;
private WindowState windowState;
private List<KeyValue<String, HeadElement>> headElements;
private boolean valid;
public PortletWindowImpl(RequestContext requestContext, ContentFragment fragment)
{
this(requestContext, fragment, null);
}
public PortletWindowImpl(RequestContext requestContext, ContentFragment fragment, PortletDefinition pd)
{
this.requestContext = requestContext;
this.id = fragment.getId();
this.portletEntityId = fragment.getFragmentId();
this.fragment = fragment;
this.pd = pd;
this.valid = pd != null;
}
public boolean isValid()
{
return valid;
}
public String getWindowId()
{
// return unique content fragment id that will
// identify a unique portlet window per page
return id;
}
/**
* Returns the identifier of this portlet instance window as object id
*
* @return the object identifier
**/
public PortletWindowID getId()
{
return this;
}
public String getPortletEntityId()
{
// return unique fragment id that will identify
// a unique fragment per portal that may appear
// in multiple pages or potentially multiple times
// in a single page
return portletEntityId;
}
public String toString()
{
return getStringId();
}
public String getStringId()
{
// return unique content fragment id that will
// identify a unique portlet window per page
return id;
}
/**
* Returns the portlet definition
*
* @return the portlet definition
**/
public PortletDefinition getPortletDefinition()
{
return pd;
}
public ContentFragment getFragment()
{
return fragment;
}
/**
* Checks if the content is instantly rendered from JPT.
*/
public boolean isInstantlyRendered()
{
return fragment.isInstantlyRendered();
}
public RequestContext getRequestContext()
{
return requestContext;
}
public PortletMode getPortletMode()
{
if (portletMode == null && valid)
{
portletMode = requestContext.getPortalURL().getNavigationalState().getMode(this);
}
return (portletMode != null ? portletMode : PortletMode.VIEW);
}
public WindowState getWindowState()
{
if (windowState == null && valid)
{
windowState = requestContext.getPortalURL().getNavigationalState().getState(this);
}
return (windowState != null ? windowState : WindowState.NORMAL);
}
public Map<String,Object> getAttributes()
{
if (attributes == null)
{
attributes = new HashMap<String,Object>();
}
return attributes;
}
public Object getAttribute(String name)
{
return getAttributes().get(name);
}
public void setAttribute(String name, Object value)
{
if (name == null)
{
throw new IllegalArgumentException("name parameter is required");
}
if (value == null)
{
getAttributes().remove(name);
}
else
{
getAttributes().put(name, value);
}
}
public void removeAttribute(String name)
{
setAttribute(name, null);
}
// --- RenderTrackable implementation
public int getRenderTimeoutCount()
{
return timeoutCount;
}
public synchronized void incrementRenderTimeoutCount()
{
timeoutCount++;
}
public synchronized void setExpiration(long expiration)
{
this.expiration = expiration;
}
public long getExpiration()
{
return this.expiration;
}
public void success()
{
timeoutCount = 0;
}
public void setRenderTimeoutCount(int timeoutCount)
{
this.timeoutCount = timeoutCount;
}
// PortletWindow invocation state
public void setInvocationState(Action action,
PortletRequestContext portletRequestContext,
PortletResponseContext portletResponseContext,
PortletRequest portletRequest, PortletResponse portletResponse,
PortletInstance portletInstance)
{
if (!valid)
{
throw new IllegalStateException("Invalid window "+getId()+" should not have been invoked");
}
this.action = action;
this.portletRequest = portletRequest;
this.portletResponseContext = portletResponseContext;
this.portletRequestContext = portletRequestContext;
this.portletResponse = portletResponse;
this.portletInstance = portletInstance;
}
public void clearInvocationState()
{
this.action = null;
this.portletRequest = null;
this.portletResponseContext = null;
this.portletRequestContext = null;
this.portletResponse = null;
this.portletInstance = null;
}
public Action getAction()
{
return action;
}
public PortletRequest getPortletRequest()
{
return portletRequest;
}
public PortletResponseContext getPortletResponseContext()
{
return portletResponseContext;
}
public PortletRequestContext getPortletRequestContext()
{
return portletRequestContext;
}
public PortletResponse getPortletResponse()
{
return portletResponse;
}
public PortletInstance getPortletInstance()
{
return portletInstance;
}
@SuppressWarnings("unchecked")
public List<KeyValue<String, HeadElement>> getHeadElements()
{
if (headElements == null && fragment != null && fragment.getPortletContent() != null)
{
PortletContent portletContent = fragment.getPortletContent();
if (portletContent.isComplete() || !Fragment.PORTLET.equals(fragment.getType()))
{
// org.apache.commons.collections.list.TreeList is well-optimized for
// fast insertions at any index in the list.
// Refer to description in the javadoc for details.
headElements = new TreeList();
HeadElementsUtils.aggregateHeadElements(headElements, fragment);
if (!headElements.isEmpty())
{
HeadElementsUtils.mergeHeadElementsByHint(headElements);
}
}
}
if (headElements == null)
{
return Collections.emptyList();
}
else
{
return headElements;
}
}
}