List<UIComponent> resourcesForAddingToHead = new ArrayList<UIComponent>();
List<UIComponent> resourcesForRelocatingToBody = new ArrayList<UIComponent>();
ExternalContext externalContext = facesContext.getExternalContext();
PortletRequest portletRequest = (PortletRequest) externalContext.getRequest();
BridgeContext bridgeContext = BridgeContext.getCurrentInstance();
PortletContainer portletContainer = bridgeContext.getPortletContainer();
// Determine whether or not the portlet container is able to add script resources to the head.
boolean portletContainerAbleToAddScriptResourceToHead = portletContainer.isAbleToAddScriptResourceToHead();
// Determine whether or not this might be a Liferay runtime portlet (which does not have the ability to add
// script resources to the head).
Boolean renderPortletResource = (Boolean) portletRequest.getAttribute(BridgeConstants.RENDER_PORTLET_RESOURCE);
boolean liferayRuntimePortlet = (renderPortletResource != null) && renderPortletResource.booleanValue();
// Note: The HeadManagedBean is a ViewScoped manage-bean that keeps a list of resources that have been added to
// the <head> section of the portal page. Note that the HeadManagedBean will be null in a JSP context since
// there is no h:head JSP component tag in JSF 2.x.
HeadManagedBean headManagedBean = HeadManagedBean.getInstance(facesContext);
Set<String> headResourceIdsFromManagedBean = null;
if (headManagedBean == null) {
headResourceIdsFromManagedBean = new HashSet<String>();
}
else {
headResourceIdsFromManagedBean = headManagedBean.getHeadResourceIds();
}
ComponentResourceFactory componentResourceFactory = (ComponentResourceFactory) FactoryExtensionFinder
.getFactory(ComponentResourceFactory.class);
// For each resource in the ViewRoot: Determine if it should added to the <head> section of the portal page,
// or if it should be relocated to the body (which is actually not a <body> element, but a <div> element
// rendered by the bridge's BodyRenderer).
for (UIComponent uiComponentResource : uiComponentResources) {
// If this is taking place during an Ajax request or this is a Liferay runtime portlet, then
if (ajaxRequest || liferayRuntimePortlet) {
// Determine whether or not the resource is already present in the <head> section of the portal page.
// Note that this can happen in one of two ways: 1) If this is NON-Liferay-Runtime portlet (currently
// doing Ajax) but has already added the resource during initial page HTTP-GET render, or 2) By another
// NON-Liferay-Runtime portlet that has already added the same JavaScript resource.
ComponentResource componentResource = componentResourceFactory.getComponentResource(
uiComponentResource);
boolean alreadyPresentInPortalPageHead = headResourceIdsFromManagedBean.contains(
componentResource.getId());
// If the resource is already present in the <head> section of the portal page, then simply output a
// logger message to this fact.
if (alreadyPresentInPortalPageHead) {
if (logger.isDebugEnabled()) {
logger.debug(
"Resource already present in head: name=[{0}] library=[{1}] rendererType=[{2}] value=[{3}] className=[{4}]",
new Object[] {
componentResource.getName(), componentResource.getLibrary(),
uiComponentResource.getRendererType(),
ComponentResourceUtil.getComponentValue(uiComponentResource),
uiComponentResource.getClass().getName(),
});
}
}
// Otherwise, since it is not possible to add it to the <head> section, the resource must be relocated
// to the body.
else {
logger.debug(
"Relocating resource to body (since it was added via Ajax and is not yet present in head): name=[{0}] library=[{1}] rendererType=[{2}] value=[{3}] className=[{4}]",
new Object[] {
componentResource.getName(), componentResource.getLibrary(),
uiComponentResource.getRendererType(),
ComponentResourceUtil.getComponentValue(uiComponentResource),
uiComponentResource.getClass().getName(),
});
resourcesForRelocatingToBody.add(uiComponentResource);
}
}
// Otherwise, if the portlet container has the ability to add resources to the <head> section of the
// portal page, then add it to the list of resources that are to be added to the <head> section.
else if (portletContainerAbleToAddScriptResourceToHead) {
resourcesForAddingToHead.add(uiComponentResource);
}
// Otherwise, we have no choice but to add it to the list of resources that are to be relocated to
// the body.
else {
resourcesForRelocatingToBody.add(uiComponentResource);
}
}
// If the portlet container has the ability to add resources to the <head> section of the portal page, then
if (portletContainerAbleToAddScriptResourceToHead) {
// Save a temporary reference to the ResponseWriter provided by the FacesContext.
ResponseWriter responseWriterBackup = facesContext.getResponseWriter();
// Replace the ResponseWriter in the FacesContext with a HeadResponseWriter that knows how to write to
// the <head>...</head> section of the rendered portal page.
HeadResponseWriter headResponseWriter = (HeadResponseWriter) portletRequest.getAttribute(
HeadResponseWriter.class.getName());
if (headResponseWriter == null) {
headResponseWriter = (HeadResponseWriter) portletContainer.getHeadResponseWriter(responseWriterBackup);
}
portletRequest.setAttribute(HeadResponseWriter.class.getName(), headResponseWriter);
facesContext.setResponseWriter(headResponseWriter);