/** @author Neil Griffin */ @ManagedBean(name = "customersModelBean") @RequestScoped public class CustomersModelBean implements Serializable { // serialVersionUID private static final long serialVersionUID = 2241487919972557504L; // Logger private static final Logger logger = LoggerFactory.getLogger(CustomersModelBean.class); // Injections @ManagedProperty(name = "customerService", value = "#{customerService}") private CustomerService customerService; // Private Bean Properties private List<Customer> allCustomers; private String selectedCustomerId; @PostConstruct public void postConstruct() { logger.trace("@PostConstruct annotation worked"); allCustomers = customerService.getAllCustomers(); } @PreDestroy public void preDestroy() { logger.trace("@PreDestroy annotation worked"); } public List<Customer> getAllCustomers() { return allCustomers; } public void setCustomerService(CustomerService customerService) { // Injected via ManagedProperty annotation this.customerService = customerService; } public String getSelectedCustomerId() { return selectedCustomerId; } public void setSelectedCustomerId(String selectedCustomerId) { this.selectedCustomerId = selectedCustomerId; } }
/** @author Neil Griffin */ @ManagedBean(name = "docLibBackingBean") @RequestScoped public class DocLibBackingBean { // Logger private static final Logger logger = LoggerFactory.getLogger(DocLibBackingBean.class); // Self-Injections private LiferayFacesContext liferayFacesContext = LiferayFacesContext.getInstance(); // Injections @ManagedProperty(name = "docLibModelBean", value = "#{docLibModelBean}") private DocLibModelBean docLibModelBean; @ManagedProperty(name = "docLibViewBean", value = "#{docLibViewBean}") private DocLibViewBean docLibViewBean; // Private Data Members private String folderName; private String folderDescription; private Boolean permittedToAddDocument; private Boolean permittedToAddFolder; // Action Listeners private AddFolderActionListener addFolderActionListener = new AddFolderActionListener(); private PopDownActionListener popDownActionListener = new PopDownActionListener(); private PopUpActionListener popUpActionListener = new PopUpActionListener(); public void treeNodeSelected(ActionEvent actionEvent) { FacesContext facesContext = FacesContext.getCurrentInstance(); ExternalContext externalContext = facesContext.getExternalContext(); long folderId = LongHelper.toLong(externalContext.getRequestParameterMap().get("folderId"), 0L); FolderTreeNode folderTreeNode = docLibModelBean.getFolderTreeModel().findFolderTreeNode(folderId); FolderUserObject folderUserObject = folderTreeNode.getFolderUserObject(); docLibModelBean.setSelectedUserObject(folderUserObject); permittedToAddFolder = null; permittedToAddDocument = null; } public AddFolderActionListener getAddFolderActionListener() { return addFolderActionListener; } public void setDocLibModelBean(DocLibModelBean docLibModelBean) { // Injected via ManagedProperty annotation this.docLibModelBean = docLibModelBean; } public void setDocLibViewBean(DocLibViewBean docLibViewBean) { // Injected via ManagedProperty annotation. this.docLibViewBean = docLibViewBean; } public String getFolderDescription() { return folderDescription; } public void setFolderDescription(String folderDescription) { this.folderDescription = folderDescription; } public String getFolderName() { return folderName; } public void setFolderName(String folderName) { this.folderName = folderName; } public PopDownActionListener getPopDownActionListener() { return popDownActionListener; } public PopUpActionListener getPopUpActionListener() { return popUpActionListener; } public boolean isPermittedToAddFolder() { if (permittedToAddFolder == null) { try { PermissionChecker permissionChecker = liferayFacesContext.getPermissionChecker(); DLFolder selectedDLFolder = docLibModelBean.getSelectedFolderUserObject().getDlFolder(); long scopeGroupId = selectedDLFolder.getGroupId(); long folderId = selectedDLFolder.getFolderId(); permittedToAddFolder = DLFolderPermission.contains( permissionChecker, scopeGroupId, folderId, ActionKeys.ADD_FOLDER); } catch (Exception e) { logger.error(e.getMessage(), e); } } return permittedToAddFolder; } public boolean isPermittedToAddDocument() { if (permittedToAddDocument == null) { try { PermissionChecker permissionChecker = liferayFacesContext.getPermissionChecker(); DLFolder selectedDLFolder = docLibModelBean.getSelectedFolderUserObject().getDlFolder(); long scopeGroupId = selectedDLFolder.getGroupId(); long folderId = selectedDLFolder.getFolderId(); permittedToAddDocument = DLFolderPermission.contains( permissionChecker, scopeGroupId, folderId, ActionKeys.ADD_DOCUMENT); permittedToAddFolder = DLFolderPermission.contains( permissionChecker, scopeGroupId, folderId, ActionKeys.ADD_FOLDER); } catch (Exception e) { logger.error(e.getMessage(), e); } } return permittedToAddDocument; } protected class AddFolderActionListener implements ActionListener { public void processAction(ActionEvent actionEvent) throws AbortProcessingException { try { FolderUserObject folderUserObject = docLibModelBean.getSelectedFolderUserObject(); DLFolder dlFolder = folderUserObject.getDlFolder(); long groupId = dlFolder.getGroupId(); long repositoryId = dlFolder.getRepositoryId(); boolean mountPoint = dlFolder.getMountPoint(); long parentFolderId = dlFolder.getFolderId(); ServiceContext serviceContext = new ServiceContext(); // Temporary: Make the default setting be that community members can view the file. Need to // develop a // "Viewable By" permissions Facelet composite component UI similar to // portal-web/docroot/html/taglib/ui/input_permissions/page.jsp serviceContext.setAddGroupPermissions(true); DLFolderServiceUtil.addFolder( groupId, repositoryId, mountPoint, parentFolderId, folderName, folderDescription, serviceContext); docLibModelBean.forceTreeRequery(); logger.debug("Added folderName=[{0}] description=[{1}]", folderName, folderDescription); } catch (Exception e) { logger.error(e.getMessage(), e); liferayFacesContext.addGlobalUnexpectedErrorMessage(); } docLibViewBean.setPopupRendered(false); } } protected class PopDownActionListener implements ActionListener { public void processAction(ActionEvent actionEvent) throws AbortProcessingException { docLibViewBean.setPopupRendered(false); } } protected class PopUpActionListener implements ActionListener { public void processAction(ActionEvent actionEvent) throws AbortProcessingException { docLibViewBean.setPopupRendered(true); } } }
/** * This class is a JSF {@link PhaseListener} that listens to the {@link PhaseId#INVOKE_APPLICATION} * and {@link PhaseId#RENDER_RESPONSE} phases of the JSF lifecycle. Along with {@link * HeadManagedBean} and {@link HeadRendererBridgeImpl}, this class helps provides a solution to an * issue regarding Ajax-initiated execution of navigation-rules in a portlet. When a portal page is * first rendered by the portal, all of the portlets on the page participate in the {@link * PortletRequest#RENDER_PHASE} of the Portlet lifecycle. During this initial HTTP-GET operation, * the bridge has the ability to add JavaScript and CSS resources to the <head> section of the * rendered portal page. Subsequent Ajax-initiated execution of the JSF lifecycle via the {@link * PortletRequest#RESOURCE_PHASE} are NOT ABLE add resources to the to the <head> section. * * @see http://issues.liferay.com/browse/FACES-180 * @author Neil Griffin */ public class HeadPhaseListener implements PhaseListener { // serialVersionUID private static final long serialVersionUID = 8502242430265622811L; // Logger private static final Logger logger = LoggerFactory.getLogger(HeadPhaseListener.class); public void afterPhase(PhaseEvent phaseEvent) { // This method just does some logging. It's useful to the developer to determine if a // navigation-rule // fired, causing new JSF view to be restored after the INVOKE_APPLICATION phase finished. if (logger.isDebugEnabled() && (phaseEvent.getPhaseId() == PhaseId.INVOKE_APPLICATION)) { FacesContext facesContext = phaseEvent.getFacesContext(); String viewId = facesContext.getViewRoot().getViewId(); logger.debug("After INVOKE_APPLICATION: viewId=[{0}]", viewId); } } public void beforePhase(PhaseEvent phaseEvent) { Bridge.PortletPhase portletRequestPhase = BridgeUtil.getPortletRequestPhase(); if ((portletRequestPhase == Bridge.PortletPhase.RENDER_PHASE) || (portletRequestPhase == Bridge.PortletPhase.RESOURCE_PHASE)) { // If about to execute the INVOKE_APPLICATION phase of the JSF lifecycle, then if (phaseEvent.getPhaseId() == PhaseId.INVOKE_APPLICATION) { beforeInvokeApplicationPhase(phaseEvent); } else if (phaseEvent.getPhaseId() == PhaseId.RENDER_RESPONSE) { beforeRenderResponsePhase(phaseEvent); } } } /** * This method is called before the {@link PhaseId#INVOKE_APPLICATION} phase of the JSF lifecycle * is executed. The purpose of this timing is to handle the case when the user clicks on a {@link * UICommand} component (like h:commandButton or h:commandLink) that has been either * Auto-ajaxified by ICEfaces, or manually Ajaxified by the developer using code like the * following: * * <p><code><f:ajax execute="@form" render=" @form" /></code> * * <p>When this happens, we need to somehow remember the list of JavaScript and/or CSS resources * that are currently in the <head> section of the portal page. This is because a * navigation-rule might fire which could cause a new view to be rendered in the {@link * PhaseId#RENDER_RESPONSE} phase that is about to follow this {@link PhaseId#INVOKE_APPLICATION} * phase. The list of resources would be contained in the {@link HeadManagedBean} {@link * ViewScoped} instance that is managed by the JSF managed-bean facility. The list would have been * populated initially in the {@link HeadManagedBean} by the {@link HeadRender} during the initial * HTTP-GET of the portal page. The way we "remember" the list is by placing it into the JSF 2 * {@link Flash} scope. This scope is used because it is very short-lived and survives any * navigation-rules that might fire, thereby causing the rendering of a new JSF view. * * <p>The story is continued in the {@link #beforeRenderResponsePhase(PhaseEvent)} method below... */ protected void beforeInvokeApplicationPhase(PhaseEvent phaseEvent) { // Get the list of resourceIds that might be contained in the Flash scope. Note that they would // have been // placed into the Flash scope by this very same method, except during in the case below for the // RENDER_RESPONSE phase. FacesContext facesContext = phaseEvent.getFacesContext(); Flash flash = facesContext.getExternalContext().getFlash(); @SuppressWarnings("unchecked") Set<String> headResourceIdsFromFlash = (Set<String>) flash.get("HEAD_RESOURCE_IDS"); // Log the viewId so that it can be visually compared with the value that is to be logged after // the // INVOKE_APPLICATION phase completes. logger.debug("Before INVOKE_APPLICATION: viewId=[{0}]", facesContext.getViewRoot().getViewId()); // If the Flash scope does not yet contain a list of head resourceIds, then the scope needs to // be populated // with a list so that the {@link #beforeRenderResponsePhase(PhaseEvent)} method below can // retrieve it. if (headResourceIdsFromFlash == null) { HeadManagedBean headManagedBean = HeadManagedBean.getInstance(facesContext); // Note that in the case where a portlet RESOURCE_PHASE was invoked with a "portlet:resource" // type of URL, // there will be no HeadManagedBean available. if (headManagedBean != null) { flash.put("HEAD_RESOURCE_IDS", headManagedBean.getHeadResourceIds()); } } } /** * This method is called before the {@link PhaseId#RENDER_RESPONSE} phase of the JSF lifecycle is * executed. The purpose of this timing is to pick up where the {@link * #beforeInvokeApplicationPhase(PhaseEvent)} method left off. It might be the case that a * navigation-rule has fired and a NEW JSF view has been loaded up after the INVOKE_APPLICATION * phase completed. If this is the case, then the list of head resourceIds in the {@link * HeadManagedBean} needs to be repopulated from the list found in the Flash scope. */ protected void beforeRenderResponsePhase(PhaseEvent phaseEvent) { FacesContext facesContext = phaseEvent.getFacesContext(); Flash flash = facesContext.getExternalContext().getFlash(); String viewId = facesContext.getViewRoot().getViewId(); @SuppressWarnings("unchecked") Set<String> headResourceIdsFromFlash = (Set<String>) flash.get("HEAD_RESOURCE_IDS"); if (headResourceIdsFromFlash != null) { HeadManagedBean headManagedBean = HeadManagedBean.getInstance(facesContext); Set<String> managedBeanResourceIds = headManagedBean.getHeadResourceIds(); for (String resourceIdFromFlash : headResourceIdsFromFlash) { if (!managedBeanResourceIds.contains(resourceIdFromFlash)) { managedBeanResourceIds.add(resourceIdFromFlash); logger.debug( "Added resourceId=[{0}] from the Flash scope to the list of resourceIds in the HeadManagedBean for viewId=[{1}]", resourceIdFromFlash, viewId); } } } } public PhaseId getPhaseId() { return PhaseId.ANY_PHASE; } }
/** @author Neil Griffin */ public class BridgeRequestScopeImpl extends ConcurrentHashMap<String, Object> implements BridgeRequestScope { // serialVersionUID private static final long serialVersionUID = 7113251688518329851L; // Logger private static final Logger logger = LoggerFactory.getLogger(BridgeRequestScopeImpl.class); // Private Constants for Bridge Request Scope Attributes private static final String BRIDGE_REQ_SCOPE_ATTR_ACTION_PARAMS = "com.liferay.faces.bridge.actionParams"; private static final String BRIDGE_REQ_SCOPE_ATTR_FACES_CONTEXT_ATTRIBUTES = "com.liferay.faces.bridge.facescontext.attributes"; private static final String BRIDGE_REQ_SCOPE_ATTR_FACES_MESSAGES = "com.liferay.faces.bridge.faces.messages"; private static final String BRIDGE_REQ_SCOPE_ATTR_FACES_VIEW_ROOT = "com.liferay.faces.bridge.faces.view.root"; private static final String BRIDGE_REQ_SCOPE_ATTR_REQUEST_ATTRIBUTES = "com.liferay.faces.bridge.faces.request.attributes"; // Private Constants for EXCLUDED namespaces listed in Section 5.1.2 of the JSR 329 Spec private static final String EXCLUDED_NAMESPACE_JAVAX_FACES = "javax.faces"; private static final String EXCLUDED_NAMESPACE_JAVAX_PORTLET = "javax.portlet"; private static final String EXCLUDED_NAMESPACE_JAVAX_PORTLET_FACES = "javax.portlet.faces"; private static final String EXCLUCED_NAMESPACE_JAVAX_SERVLET = "javax.servlet"; private static final String EXCLUCED_NAMESPACE_JAVAX_SERVLET_INCLUDE = "javax.servlet.include"; private static List<String> STANDARD_EXCLUDED_REQUEST_ATTRIBUTE_NAMESPACES = new ArrayList<String>(3); // Other Private Constants private static final String JAVAX_FACES_ENCODED_URL_PARAM = "javax.faces.encodedURL"; static { // Build up the static list of standard excluded request attribute namespaces. STANDARD_EXCLUDED_REQUEST_ATTRIBUTE_NAMESPACES.add(EXCLUDED_NAMESPACE_JAVAX_FACES); STANDARD_EXCLUDED_REQUEST_ATTRIBUTE_NAMESPACES.add(EXCLUDED_NAMESPACE_JAVAX_PORTLET); STANDARD_EXCLUDED_REQUEST_ATTRIBUTE_NAMESPACES.add(EXCLUDED_NAMESPACE_JAVAX_PORTLET_FACES); STANDARD_EXCLUDED_REQUEST_ATTRIBUTE_NAMESPACES.add(EXCLUCED_NAMESPACE_JAVAX_SERVLET); STANDARD_EXCLUDED_REQUEST_ATTRIBUTE_NAMESPACES.add(EXCLUCED_NAMESPACE_JAVAX_SERVLET_INCLUDE); } // Private Data Members private Map<String, Object> attributeMap; private boolean beganInActionOrEventRequest; private List<String> excludedAttributeNames; private Flash flash; private String idPrefix; private String idSuffix; private Map<String, Object> managedBeanMap; private PortletMode portletMode; private boolean portletModeChanged; private Set<String> preExistingAttributeNames; private boolean redirect; public BridgeRequestScopeImpl( PortletConfig portletConfig, PortletContext portletContext, PortletRequest portletRequest, String idPrefix) { this.attributeMap = new HashMap<String, Object>(); long timeInMillis = Calendar.getInstance().getTimeInMillis(); this.idPrefix = idPrefix; this.idSuffix = Long.toString(timeInMillis); BridgeConfigFactory bridgeConfigFactory = (BridgeConfigFactory) BridgeFactoryFinder.getFactory(BridgeConfigFactory.class); BridgeConfig bridgeConfig = bridgeConfigFactory.getBridgeConfig(); this.excludedAttributeNames = new ArrayList<String>(); // Get the list of excluded BridgeRequestScope attributes from the faces-config.xml descriptors. Set<String> facesConfigExcludedAttributeNames = bridgeConfig.getExcludedRequestAttributes(); // Get the list of excluded BridgeRequestScope attributes from the WEB-INF/portlet.xml // descriptor. @SuppressWarnings("unchecked") List<String> portletContextExcludedAttributeNames = (List<String>) portletContext.getAttribute( Bridge.BRIDGE_PACKAGE_PREFIX + portletConfig.getPortletName() + BridgeConstants.CHAR_PERIOD + Bridge.EXCLUDED_REQUEST_ATTRIBUTES); // Combine the two lists into a single list of excluded BridgeRequestScope attributes. if (facesConfigExcludedAttributeNames != null) { this.excludedAttributeNames.addAll(facesConfigExcludedAttributeNames); } if (portletContextExcludedAttributeNames != null) { this.excludedAttributeNames.addAll(portletContextExcludedAttributeNames); } this.preExistingAttributeNames = getPreExistingRequestAttributeNames(portletRequest); Bridge.PortletPhase portletPhase = (Bridge.PortletPhase) portletRequest.getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE); if ((portletPhase == Bridge.PortletPhase.ACTION_PHASE) || (portletPhase == Bridge.PortletPhase.EVENT_PHASE)) { beganInActionOrEventRequest = true; } } /** * The overrides for {@link #toString()} and {@link #hashCode()} are necessary because the {@link * ConcurrentHashMap} parent class overrides them and causes debug logs to be difficult to * interpret. */ @Override public int hashCode() { return System.identityHashCode(this); } /** * Saves the state of the FacesContext as required by section 5.1.2 of the JSR 329 spec. This * method is designed to be called during the ACTION_PHASE of the portlet lifecycle. * * @param facesContext The current faces context. */ public void preserveScopedData(FacesContext facesContext) { logger.debug("preserveScopedData(facesContext)"); // Get the ExternalContext. ExternalContext externalContext = facesContext.getExternalContext(); // Save the view root. setAttribute(BRIDGE_REQ_SCOPE_ATTR_FACES_VIEW_ROOT, facesContext.getViewRoot()); // If the PortletMode hasn't changed, then preserve the "javax.faces.ViewState" request // parameter value. if (!portletModeChanged) { PortletResponse portletResponse = (PortletResponse) facesContext.getExternalContext().getResponse(); if (portletResponse instanceof ActionResponse) { String viewState = facesContext .getExternalContext() .getRequestParameterMap() .get(ResponseStateManager.VIEW_STATE_PARAM); if (viewState != null) { // NOTE: Although it is possible to save this as a render parameter, can't use that // approach because // portlet containers like Pluto will add the "javax.faces.ViewState" parameter to any // ResourceURLs // that are created during the RENDER_PHASE of the portlet lifecycle. setAttribute(ResponseStateManager.VIEW_STATE_PARAM, viewState); } } } // If specified in the WEB-INF/portlet.xml descriptor, then preserve the action parameters. BridgeContext bridgeContext = (BridgeContext) facesContext.getAttributes().get(BridgeExt.BRIDGE_CONTEXT_ATTRIBUTE); if (bridgeContext.isPreserveActionParams()) { Map<String, String> actionRequestParameterMap = new HashMap<String, String>(externalContext.getRequestParameterMap()); actionRequestParameterMap.remove(ResponseStateManager.VIEW_STATE_PARAM); actionRequestParameterMap.remove(JAVAX_FACES_ENCODED_URL_PARAM); setAttribute(BRIDGE_REQ_SCOPE_ATTR_ACTION_PARAMS, actionRequestParameterMap); } // Save the list of faces messages. List<FacesMessageWrapper> facesMessageWrappers = new ArrayList<FacesMessageWrapper>(); Iterator<String> clientIds = facesContext.getClientIdsWithMessages(); while (clientIds.hasNext()) { String clientId = clientIds.next(); Iterator<FacesMessage> facesMessages = facesContext.getMessages(clientId); while (facesMessages.hasNext()) { FacesMessage facesMessage = facesMessages.next(); FacesMessageWrapper facesMessageWrapper = new FacesMessageWrapper(clientId, facesMessage); facesMessageWrappers.add(facesMessageWrapper); } } if (facesMessageWrappers.size() > 0) { setAttribute(BRIDGE_REQ_SCOPE_ATTR_FACES_MESSAGES, facesMessageWrappers); } else { logger.trace("Not saving any faces messages"); } // Save the non-excluded request attributes. This would include, for example, managed-bean // instances that may // have been created during the ACTION_PHASE that need to survive to the RENDER_PHASE. if ((!redirect) && (!portletModeChanged)) { Map<String, Object> currentRequestAttributes = externalContext.getRequestMap(); if (currentRequestAttributes != null) { List<RequestAttribute> savedRequestAttributes = new ArrayList<RequestAttribute>(); Iterator<Map.Entry<String, Object>> itr = currentRequestAttributes.entrySet().iterator(); if (itr != null) { while (itr.hasNext()) { Map.Entry<String, Object> mapEntry = itr.next(); String name = mapEntry.getKey(); Object value = mapEntry.getValue(); if (isExcludedRequestAttribute(name, value)) { logger.trace("Not saving EXCLUDED attribute name=[{0}]", name); } else if ((value != null) && (value.getClass().getAnnotation(ExcludeFromManagedRequestScope.class) != null)) { logger.trace( "Not saving EXCLUDED attribute name=[{0}] due to ExcludeFromManagedRequestScope annotation", name); } else { logger.trace( "Saving non-excluded request attribute name=[{0}] value=[{1}]", name, value); savedRequestAttributes.add(new RequestAttribute(name, value)); } } if (savedRequestAttributes.size() > 0) { setAttribute(BRIDGE_REQ_SCOPE_ATTR_REQUEST_ATTRIBUTES, savedRequestAttributes); } else { logger.trace("Not saving any non-excluded request attributes"); } } } else { logger.trace( "Not saving any non-excluded request attributes because there are no request attributes!"); } } else { logger.trace("Not saving any non-excluded request attributes due to redirect"); } // NOTE: PROPOSED-FOR-BRIDGE3-API: https://issues.apache.org/jira/browse/PORTLETBRIDGE-203 Build // up a list of // attributes found in the FacesContext attribute map and save them. It has to be copied in this // manner because // the Faces implementation likely calls the clear() method during the call to its // FacesContextImpl.release() // method. Map<Object, Object> currentFacesContextAttributes = facesContext.getAttributes(); int mapSize = currentFacesContextAttributes.size(); List<FacesContextAttribute> savedFacesContextAttributes = new ArrayList<FacesContextAttribute>(mapSize); Iterator<Map.Entry<Object, Object>> itr = currentFacesContextAttributes.entrySet().iterator(); while (itr.hasNext()) { Map.Entry<Object, Object> mapEntry = itr.next(); Object name = mapEntry.getKey(); Object value = mapEntry.getValue(); logger.trace("Saving FacesContext attribute name=[{0}] value=[{1}]", name, value); savedFacesContextAttributes.add(new FacesContextAttribute(name, value)); } setAttribute(BRIDGE_REQ_SCOPE_ATTR_FACES_CONTEXT_ATTRIBUTES, savedFacesContextAttributes); } /** * Restores the state of the FacesContext as required by section 5.1.2 of the JSR 329 spec. This * method is designed to be called during the RENDER_PHASE of the portlet lifecycle. * * @param facesContext The current faces context. * @return Flag indicating whether or not a restoration took place. */ @SuppressWarnings("unchecked") public boolean restoreScopedData(FacesContext facesContext) { if (beganInActionOrEventRequest) { // Restore the view root that may have been saved during the ACTION_PHASE of the portlet // lifecycle. UIViewRoot uiViewRoot = (UIViewRoot) getAttribute(BRIDGE_REQ_SCOPE_ATTR_FACES_VIEW_ROOT); if (uiViewRoot != null) { facesContext.setViewRoot(uiViewRoot); logger.debug("Restored viewId=[{0}] uiViewRoot=[{1}]", uiViewRoot.getViewId(), uiViewRoot); } else { logger.debug("Did not restore uiViewRoot"); } // Restore the faces messages that may have been saved during the ACTION_PHASE of the portlet // lifecycle. List<FacesMessageWrapper> facesMessages = (List<FacesMessageWrapper>) getAttribute(BRIDGE_REQ_SCOPE_ATTR_FACES_MESSAGES); boolean restoredFacesMessages = false; if (facesMessages != null) { for (FacesMessageWrapper facesMessageWrapper : facesMessages) { String clientId = facesMessageWrapper.getClientId(); FacesMessage facesMessage = facesMessageWrapper.getFacesMessage(); facesContext.addMessage(clientId, facesMessage); logger.trace("Restored facesMessage=[{0}]", facesMessage.getSummary()); restoredFacesMessages = true; } } if (restoredFacesMessages) { logger.debug("Restored facesMessages"); } else { logger.debug("Did not restore any facesMessages"); } // Restore the non-excluded request attributes. List<RequestAttribute> savedRequestAttributes = (List<RequestAttribute>) getAttribute(BRIDGE_REQ_SCOPE_ATTR_REQUEST_ATTRIBUTES); boolean restoredNonExcludedRequestAttributes = false; if (savedRequestAttributes != null) { Map<String, Object> currentRequestAttributes = facesContext.getExternalContext().getRequestMap(); for (RequestAttribute requestAttribute : savedRequestAttributes) { String name = requestAttribute.getName(); Object value = requestAttribute.getValue(); logger.trace( "Restoring non-excluded request attribute name=[{0}] value=[{1}]", name, value); currentRequestAttributes.put(name, value); restoredNonExcludedRequestAttributes = true; } } if (restoredNonExcludedRequestAttributes) { logger.debug("Restored non-excluded request attributes"); } else { logger.debug("Did not restore any non-excluded request attributes"); } // NOTE: PROPOSE-FOR-BRIDGE3-API: https://issues.apache.org/jira/browse/PORTLETBRIDGE-203 // Restore the // FacesContext attributes that may have been saved during the ACTION_PHASE of the portlet // lifecycle. List<FacesContextAttribute> savedFacesContextAttributes = (List<FacesContextAttribute>) getAttribute(BRIDGE_REQ_SCOPE_ATTR_FACES_CONTEXT_ATTRIBUTES); boolean restoredFacesContextAttibutes = false; if (savedFacesContextAttributes != null) { Map<Object, Object> currentFacesContextAttributes = facesContext.getAttributes(); for (FacesContextAttribute facesContextAttribute : savedFacesContextAttributes) { Object name = facesContextAttribute.getName(); // Note: Don't want to restore the BridgeContext because that would be invalid data -- it // would // contain the ActionRequest/ActionResponse or EventRequest/EventResponse and would // overwrite the // current RenderRequest/RenderResponse. if (!BridgeExt.BRIDGE_CONTEXT_ATTRIBUTE.equals(name)) { Object value = facesContextAttribute.getValue(); logger.trace("Restoring FacesContext attribute name=[{0}] value=[{1}]", name, value); currentFacesContextAttributes.put(name, value); restoredFacesContextAttibutes = true; } } } if (restoredFacesContextAttibutes) { logger.debug("Restored FacesContext attributes"); } else { logger.debug("Did not restore any FacesContext attributes"); } return true; } else { return false; } } /** * The overrides for {@link #toString()} and {@link #hashCode()} are necessary because the {@link * ConcurrentHashMap} parent class overrides them and causes debug logs to be difficult to * interpret. */ @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(getClass().getName()); buf.append(BridgeConstants.CHAR_AT); buf.append(Integer.toHexString(hashCode())); return buf.toString(); } public Object getAttribute(String key) { return attributeMap.get(key); } public void setAttribute(String key, Object value) { attributeMap.put(key, value); } protected boolean isExcludedRequestAttribute(String attributeName, Object value) { boolean excluded = false; if (!excluded) { if (excludedAttributeNames != null) { for (String excludedAttribute : excludedAttributeNames) { if (attributeName.equals(excludedAttribute)) { excluded = true; break; } else if (excludedAttribute.endsWith(BridgeConstants.CHAR_ASTERISK)) { String wildcardNamespace = excludedAttribute; int dotPos = wildcardNamespace.lastIndexOf(BridgeConstants.CHAR_PERIOD); if (dotPos > 0) { wildcardNamespace = wildcardNamespace.substring(0, dotPos); } if (isNamespaceMatch(attributeName, wildcardNamespace)) { excluded = true; break; } } } } } if (!excluded) { for (String namespace : STANDARD_EXCLUDED_REQUEST_ATTRIBUTE_NAMESPACES) { if (isNamespaceMatch(attributeName, namespace)) { excluded = true; break; } } } if (!excluded) { excluded = preExistingAttributeNames.contains(attributeName); } if (!excluded) { // EXCLUDED attributes listed in Section 5.1.2 of the JSR 329 Spec excluded = ((value != null) && ((value instanceof ExternalContext) || (value instanceof FacesContext) || (value instanceof HttpSession) || (value instanceof PortalContext) || (value instanceof PortletConfig) || (value instanceof PortletContext) || (value instanceof PortletPreferences) || (value instanceof PortletRequest) || (value instanceof PortletResponse) || (value instanceof PortletSession) || (value instanceof ServletConfig) || (value instanceof ServletContext) || (value instanceof ServletRequest) || (value instanceof ServletResponse))); } return excluded; } public Flash getFlash() { return flash; } public void setFlash(Flash flash) { this.flash = flash; } protected boolean isNamespaceMatch(String attributeName, String namespace) { boolean match = false; String attributeNamespace = attributeName; int dotPos = attributeNamespace.lastIndexOf(BridgeConstants.CHAR_PERIOD); if (dotPos > 0) { attributeNamespace = attributeNamespace.substring(0, dotPos); } if (namespace.equals(attributeNamespace)) { match = true; } return match; } public String getId() { return idPrefix + idSuffix; } public void setIdPrefix(String idPrefix) { this.idPrefix = idPrefix; } public Map<String, Object> getManagedBeanMap() { if (managedBeanMap == null) { managedBeanMap = new HashMap<String, Object>(); } return managedBeanMap; } public PortletMode getPortletMode() { return portletMode; } public void setPortletMode(PortletMode portletMode) { this.portletMode = portletMode; } public void setPortletModeChanged(boolean portletModeChanged) { this.portletModeChanged = portletModeChanged; } /** * According to section 5.1.2 of the JSR 329 spec, the request attributes that exist before the * bridge acquires the FacesContext must not be part of the bridge request scope. Having noted * that, we have to save-off a list of names of these pre-existing request attributes, so that we * know to NOT restore them. */ protected Set<String> getPreExistingRequestAttributeNames(PortletRequest portletRequest) { Set<String> attributeNames = null; Enumeration<String> requestAttributeNames = portletRequest.getAttributeNames(); if (requestAttributeNames != null) { attributeNames = new HashSet<String>(); while (requestAttributeNames.hasMoreElements()) { String attributeName = requestAttributeNames.nextElement(); attributeNames.add(attributeName); logger.trace("Saving name of pre-existing request attribute [{0}]", attributeName); } } return attributeNames; } @SuppressWarnings("unchecked") public Map<String, String> getPreservedActionParameterMap() { return (Map<String, String>) getAttribute(BRIDGE_REQ_SCOPE_ATTR_ACTION_PARAMS); } public String getPreservedViewStateParam() { return (String) getAttribute(ResponseStateManager.VIEW_STATE_PARAM); } public void setRedirect(boolean redirect) { this.redirect = redirect; } }
/** @author Neil Griffin */ public class RequestParameterMapMultiPartImpl extends RequestParameterMap { // Logger private static final Logger logger = LoggerFactory.getLogger(RequestParameterMapMultiPartImpl.class); // Private Constants private static final String CONTEXT_PARAM_UPLOADED_FILES_DIR = "javax.faces.UPLOADED_FILES_DIR"; private static final String CONTEXT_PARAM_UPLOADED_FILE_MAX_SIZE = "javax.faces.UPLOADED_FILE_MAX_SIZE"; private static final String JAVA_IO_TMPDIR = "java.io.tmpdir"; private static final int DEFAULT_FILE_MAX_SIZE = 104857600; // 100MB // Private Data Members private Map<String, String> requestParameterMap; private Map<String, List<UploadedFile>> requestParameterFileMap; @SuppressWarnings("unchecked") public RequestParameterMapMultiPartImpl( BridgeContext bridgeContext, ClientDataRequest clientDataRequest) { try { PortletSession portletSession = clientDataRequest.getPortletSession(); PortletContext portletContext = portletSession.getPortletContext(); // Determine the uploaded files directory path according to the JSF 2.2 proposal: // https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=690 String uploadedFilesDir = portletContext.getInitParameter(CONTEXT_PARAM_UPLOADED_FILES_DIR); if (uploadedFilesDir == null) { uploadedFilesDir = System.getProperty(JAVA_IO_TMPDIR); if (logger.isDebugEnabled()) { logger.debug( "The web.xml context-param name=[{0}] not found, using default system property=[{1}] value=[{2}]", new Object[] {CONTEXT_PARAM_UPLOADED_FILES_DIR, JAVA_IO_TMPDIR, uploadedFilesDir}); } } else { if (logger.isDebugEnabled()) { logger.debug( "Using web.xml context-param name=[{0}] value=[{1}]", new Object[] {CONTEXT_PARAM_UPLOADED_FILES_DIR, uploadedFilesDir}); } } // Using the portlet sessionId, determine a unique folder path and create the path if it does // not exist. String sessionId = portletSession.getId(); File uploadedFilesPath = new File(uploadedFilesDir, sessionId); if (!uploadedFilesPath.exists()) { try { uploadedFilesPath.mkdirs(); } catch (SecurityException e) { uploadedFilesDir = System.getProperty(JAVA_IO_TMPDIR); logger.error( "Security exception message=[{0}] when trying to create unique path=[{1}] so using default system property=[{2}] value=[{3}]", new Object[] { e.getMessage(), uploadedFilesPath.toString(), JAVA_IO_TMPDIR, uploadedFilesDir }); uploadedFilesPath = new File(uploadedFilesDir, sessionId); uploadedFilesPath.mkdirs(); } } // Initialize commons-fileupload with the file upload path. DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory(); diskFileItemFactory.setRepository(uploadedFilesPath); // Initialize commons-fileupload so that uploaded temporary files are not automatically // deleted. diskFileItemFactory.setFileCleaningTracker(null); // Initialize the commons-fileupload size threshold to zero, so that all files will be dumped // to disk // instead of staying in memory. diskFileItemFactory.setSizeThreshold(0); // Determine the max file upload size threshold in bytes. String uploadedFilesMaxSize = portletContext.getInitParameter(CONTEXT_PARAM_UPLOADED_FILE_MAX_SIZE); int fileMaxSize = DEFAULT_FILE_MAX_SIZE; if (uploadedFilesMaxSize == null) { if (logger.isDebugEnabled()) { logger.debug( "The web.xml context-param name=[{0}] not found, using default=[{1}] bytes", new Object[] {CONTEXT_PARAM_UPLOADED_FILE_MAX_SIZE, DEFAULT_FILE_MAX_SIZE}); } } else { try { fileMaxSize = Integer.parseInt(uploadedFilesMaxSize); if (logger.isDebugEnabled()) { logger.debug( "Using web.xml context-param name=[{0}] value=[{1}] bytes", new Object[] {CONTEXT_PARAM_UPLOADED_FILE_MAX_SIZE, fileMaxSize}); } } catch (NumberFormatException e) { logger.error( "Invalid value=[{0}] for web.xml context-param name=[{1}] using default=[{2}] bytes.", new Object[] { uploadedFilesMaxSize, CONTEXT_PARAM_UPLOADED_FILE_MAX_SIZE, DEFAULT_FILE_MAX_SIZE }); } } // Parse the request parameters and save all uploaded files in a map. PortletFileUpload portletFileUpload = new PortletFileUpload(diskFileItemFactory); portletFileUpload.setFileSizeMax(fileMaxSize); requestParameterMap = new HashMap<String, String>(); requestParameterFileMap = new HashMap<String, List<UploadedFile>>(); // Get the namespace that might be found in request parameter names. String namespace = bridgeContext.getPortletContainer().getResponseNamespace(); // FACES-271: Include name+value pairs found in the ActionRequest. PortletContainer portletContainer = bridgeContext.getPortletContainer(); Set<Map.Entry<String, String[]>> actionRequestParameterSet = clientDataRequest.getParameterMap().entrySet(); for (Map.Entry<String, String[]> mapEntry : actionRequestParameterSet) { String parameterName = mapEntry.getKey(); int pos = parameterName.indexOf(namespace); if (pos >= 0) { parameterName = parameterName.substring(pos + namespace.length()); } String[] parameterValues = mapEntry.getValue(); if (parameterValues.length > 0) { String fixedRequestParameterValue = portletContainer.fixRequestParameterValue(parameterValues[0]); requestParameterMap.put(parameterName, fixedRequestParameterValue); logger.debug( "Found in ActionRequest: {0}=[{1}]", parameterName, fixedRequestParameterValue); } } UploadedFileFactory uploadedFileFactory = (UploadedFileFactory) BridgeFactoryFinder.getFactory(UploadedFileFactory.class); // Begin parsing the request for file parts: try { FileItemIterator fileItemIterator = null; if (clientDataRequest instanceof ResourceRequest) { ResourceRequest resourceRequest = (ResourceRequest) clientDataRequest; fileItemIterator = portletFileUpload.getItemIterator(new ActionRequestAdapter(resourceRequest)); } else { ActionRequest actionRequest = (ActionRequest) clientDataRequest; fileItemIterator = portletFileUpload.getItemIterator(actionRequest); } boolean optimizeNamespace = BooleanHelper.toBoolean( bridgeContext.getInitParameter( BridgeConfigConstants.PARAM_OPTIMIZE_PORTLET_NAMESPACE1), true); if (fileItemIterator != null) { int totalFiles = 0; // For each field found in the request: while (fileItemIterator.hasNext()) { try { totalFiles++; // Get the stream of field data from the request. FileItemStream fieldStream = (FileItemStream) fileItemIterator.next(); // Get field name from the field stream. String fieldName = fieldStream.getFieldName(); // If namespace optimization is enabled and the namespace is present in the field // name, // then remove the portlet namespace from the field name. if (optimizeNamespace) { int pos = fieldName.indexOf(namespace); if (pos >= 0) { fieldName = fieldName.substring(pos + namespace.length()); } } // Get the content-type, and file-name from the field stream. String contentType = fieldStream.getContentType(); boolean formField = fieldStream.isFormField(); String fileName = null; try { fileName = fieldStream.getName(); } catch (InvalidFileNameException e) { fileName = e.getName(); } // Copy the stream of file data to a temporary file. NOTE: This is necessary even if // the // current field is a simple form-field because the call below to // diskFileItem.getString() // will fail otherwise. DiskFileItem diskFileItem = (DiskFileItem) diskFileItemFactory.createItem(fieldName, contentType, formField, fileName); Streams.copy(fieldStream.openStream(), diskFileItem.getOutputStream(), true); // If the current field is a simple form-field, then save the form field value in the // map. if (diskFileItem.isFormField()) { String requestParameterValue = diskFileItem.getString(clientDataRequest.getCharacterEncoding()); String fixedRequestParameterValue = portletContainer.fixRequestParameterValue(requestParameterValue); requestParameterMap.put(fieldName, fixedRequestParameterValue); logger.debug("{0}=[{1}]", fieldName, fixedRequestParameterValue); } else { File tempFile = diskFileItem.getStoreLocation(); // If the copy was successful, then if (tempFile.exists()) { // Copy the commons-fileupload temporary file to a file in the same temporary // location, but with the filename provided by the user in the upload. This has // two // benefits: 1) The temporary file will have a nice meaningful name. 2) By copying // the file, the developer can have access to a semi-permanent file, because the // commmons-fileupload DiskFileItem.finalize() method automatically deletes the // temporary one. String tempFileName = tempFile.getName(); String tempFileAbsolutePath = tempFile.getAbsolutePath(); String copiedFileName = stripIllegalCharacters(fileName); String copiedFileAbsolutePath = tempFileAbsolutePath.replace(tempFileName, copiedFileName); File copiedFile = new File(copiedFileAbsolutePath); FileUtils.copyFile(tempFile, copiedFile); // If present, build up a map of headers. Map<String, List<String>> headersMap = new HashMap<String, List<String>>(); FileItemHeaders fileItemHeaders = fieldStream.getHeaders(); if (fileItemHeaders != null) { Iterator<String> headerNameItr = fileItemHeaders.getHeaderNames(); if (headerNameItr != null) { while (headerNameItr.hasNext()) { String headerName = headerNameItr.next(); Iterator<String> headerValuesItr = fileItemHeaders.getHeaders(headerName); List<String> headerValues = new ArrayList<String>(); if (headerValuesItr != null) { while (headerValuesItr.hasNext()) { String headerValue = headerValuesItr.next(); headerValues.add(headerValue); } } headersMap.put(headerName, headerValues); } } } // Put a valid UploadedFile instance into the map that contains all of the // uploaded file's attributes, along with a successful status. Map<String, Object> attributeMap = new HashMap<String, Object>(); String id = Long.toString(((long) hashCode()) + System.currentTimeMillis()); String message = null; UploadedFile uploadedFile = uploadedFileFactory.getUploadedFile( copiedFileAbsolutePath, attributeMap, diskFileItem.getCharSet(), diskFileItem.getContentType(), headersMap, id, message, fileName, diskFileItem.getSize(), UploadedFile.Status.FILE_SAVED); requestParameterMap.put(fieldName, copiedFileAbsolutePath); addUploadedFile(fieldName, uploadedFile); logger.debug( "Received uploaded file fieldName=[{0}] fileName=[{1}]", fieldName, fileName); } } } catch (Exception e) { logger.error(e); UploadedFile uploadedFile = uploadedFileFactory.getUploadedFile(e); String fieldName = Integer.toString(totalFiles); addUploadedFile(fieldName, uploadedFile); } } } } // If there was an error in parsing the request for file parts, then put a bogus UploadedFile // instance in // the map so that the developer can have some idea that something went wrong. catch (Exception e) { logger.error(e); UploadedFile uploadedFile = uploadedFileFactory.getUploadedFile(e); addUploadedFile("unknown", uploadedFile); } clientDataRequest.setAttribute(PARAM_UPLOADED_FILES, requestParameterFileMap); // If not found in the request, Section 6.9 of the Bridge spec requires that the value of the // ResponseStateManager.RENDER_KIT_ID_PARAM request parameter be set to the value of the // "javax.portlet.faces.<portletName>.defaultRenderKitId" PortletContext attribute. String renderKitIdParam = requestParameterMap.get(ResponseStateManager.RENDER_KIT_ID_PARAM); if (renderKitIdParam == null) { renderKitIdParam = bridgeContext.getDefaultRenderKitId(); if (renderKitIdParam != null) { requestParameterMap.put(ResponseStateManager.RENDER_KIT_ID_PARAM, renderKitIdParam); } } } catch (Exception e) { logger.error(e.getMessage(), e); } } protected void addUploadedFile(String fieldName, UploadedFile uploadedFile) { List<UploadedFile> uploadedFiles = requestParameterFileMap.get(fieldName); if (uploadedFiles == null) { uploadedFiles = new ArrayList<UploadedFile>(); requestParameterFileMap.put(fieldName, uploadedFiles); } uploadedFiles.add(uploadedFile); } @Override protected AbstractPropertyMapEntry<String> createPropertyMapEntry(String name) { return new RequestParameterMapEntryMultiPart(name, requestParameterMap); } @Override protected void removeProperty(String name) { throw new UnsupportedOperationException(); } protected String stripIllegalCharacters(String fileName) { // FACES-64: Need to strip out invalid characters. // http://technet.microsoft.com/en-us/library/cc956689.aspx String strippedFileName = fileName; if (fileName != null) { strippedFileName = fileName.replaceAll("[\\\\/\\[\\]:|<>+;=.?\"]", "-"); } return strippedFileName; } @Override protected String getProperty(String name) { return requestParameterMap.get(name); } @Override protected void setProperty(String name, String value) { throw new UnsupportedOperationException(); } @Override protected Enumeration<String> getPropertyNames() { // Note#1: Section 6.9 of the Bridge spec requires that a parameter name be added to the return // value of // ExternalContext.getRequestParameterNames() for ResponseStateManager.RENDER_KIT_ID_PARAM. This // will // automatically be the case because this class builds up its own internal requestParameterMap // in the // constructor that will contain the ResponseStateManager.RENDER_KIT_ID_PARAM if required. // Note#2: This can't be cached because the caller basically wants a new enumeration to iterate // over each time. return Collections.enumeration(requestParameterMap.keySet()); } /** * Since {@link PortletFileUpload#parseRequest(ActionRequest)} only works with {@link * ActionRequest}, this adapter class is necessary to force commons-fileupload to work with * ResourceRequest (Ajax file upload). * * @author Neil Griffin */ protected class ActionRequestAdapter implements ActionRequest { private ResourceRequest resourceRequest; public ActionRequestAdapter(ResourceRequest resourceRequest) { this.resourceRequest = resourceRequest; } public void removeAttribute(String name) { resourceRequest.removeAttribute(name); } public Object getAttribute(String name) { return resourceRequest.getAttribute(name); } public void setAttribute(String name, Object value) { resourceRequest.setAttribute(name, value); } public Enumeration<String> getAttributeNames() { return resourceRequest.getAttributeNames(); } public String getAuthType() { return resourceRequest.getAuthType(); } public String getCharacterEncoding() { return resourceRequest.getCharacterEncoding(); } public void setCharacterEncoding(String enc) throws UnsupportedEncodingException { resourceRequest.setCharacterEncoding(enc); } public int getContentLength() { return resourceRequest.getContentLength(); } public String getContentType() { return resourceRequest.getContentType(); } public String getContextPath() { return resourceRequest.getContextPath(); } public Cookie[] getCookies() { return resourceRequest.getCookies(); } public boolean isPortletModeAllowed(PortletMode mode) { return resourceRequest.isPortletModeAllowed(mode); } public boolean isRequestedSessionIdValid() { return resourceRequest.isRequestedSessionIdValid(); } public boolean isWindowStateAllowed(WindowState state) { return resourceRequest.isWindowStateAllowed(state); } public boolean isSecure() { return resourceRequest.isSecure(); } public boolean isUserInRole(String role) { return resourceRequest.isUserInRole(role); } public Locale getLocale() { return resourceRequest.getLocale(); } public Enumeration<Locale> getLocales() { return resourceRequest.getLocales(); } public String getMethod() { return resourceRequest.getMethod(); } public String getParameter(String name) { return resourceRequest.getParameter(name); } public Map<String, String[]> getParameterMap() { return resourceRequest.getParameterMap(); } public Enumeration<String> getParameterNames() { return resourceRequest.getParameterNames(); } public String[] getParameterValues(String name) { return resourceRequest.getParameterValues(name); } public PortalContext getPortalContext() { return resourceRequest.getPortalContext(); } public InputStream getPortletInputStream() throws IOException { return resourceRequest.getPortletInputStream(); } public PortletMode getPortletMode() { return resourceRequest.getPortletMode(); } public PortletSession getPortletSession() { return resourceRequest.getPortletSession(); } public PortletSession getPortletSession(boolean create) { return resourceRequest.getPortletSession(); } public PortletPreferences getPreferences() { return resourceRequest.getPreferences(); } public Map<String, String[]> getPrivateParameterMap() { return resourceRequest.getPrivateParameterMap(); } public Enumeration<String> getProperties(String name) { return resourceRequest.getProperties(name); } public String getProperty(String name) { return resourceRequest.getProperty(name); } public Enumeration<String> getPropertyNames() { return resourceRequest.getPropertyNames(); } public Map<String, String[]> getPublicParameterMap() { return resourceRequest.getPublicParameterMap(); } public BufferedReader getReader() throws UnsupportedEncodingException, IOException { return resourceRequest.getReader(); } public String getRemoteUser() { return resourceRequest.getRemoteUser(); } public String getRequestedSessionId() { return resourceRequest.getRequestedSessionId(); } public String getResponseContentType() { return resourceRequest.getResponseContentType(); } public Enumeration<String> getResponseContentTypes() { return resourceRequest.getResponseContentTypes(); } public String getScheme() { return resourceRequest.getScheme(); } public String getServerName() { return resourceRequest.getServerName(); } public int getServerPort() { return resourceRequest.getServerPort(); } public Principal getUserPrincipal() { return resourceRequest.getUserPrincipal(); } public String getWindowID() { return resourceRequest.getWindowID(); } public WindowState getWindowState() { return resourceRequest.getWindowState(); } } }
/** @author Neil Griffin */ public class DocumentDataModel extends LazyDataModel<DocLibFileEntry> implements Serializable { // serialVersionUID private static final long serialVersionUID = 4895165386116316346L; // Logger private static final Logger logger = LoggerFactory.getLogger(DocumentDataModel.class); // Private Data Members private DLFolder dlFolder; private String portalURL; private String pathContext; private PermissionChecker permissionChecker; public DocumentDataModel( DLFolder dlFolder, int rowsPerPage, String portalURL, String pathContext, PermissionChecker permissionChecker) { this.dlFolder = dlFolder; setRowsPerPage(rowsPerPage); this.portalURL = portalURL; this.pathContext = pathContext; this.permissionChecker = permissionChecker; setSortColumn("title"); setSortAscending(true); } @Override public int countRows() { return findViewableDocuments().size(); } @Override public void deleteRow(Object primaryKey) throws IOException { long fileEntryId = (Long) primaryKey; try { DLFileEntry dlFileEntry = DLFileEntryLocalServiceUtil.getFileEntry(fileEntryId); DLFileEntryServiceUtil.deleteFileEntry( dlFolder.getGroupId(), dlFolder.getFolderId(), dlFileEntry.getName()); } catch (Exception e) { logger.error(e.getMessage(), e); throw new IOException(e.getMessage()); } } @Override public List<DocLibFileEntry> findRows(int startRow, int finishRow) { List<DocLibFileEntry> viewableDocuments = findViewableDocuments(); int totalViewableDocuments = viewableDocuments.size(); if ((totalViewableDocuments > 0) && (startRow != QueryUtil.ALL_POS) && (finishRow != QueryUtil.ALL_POS)) { if (startRow > totalViewableDocuments) { startRow = totalViewableDocuments; } if (finishRow > totalViewableDocuments) { finishRow = totalViewableDocuments; } int includeFinishRowToo = finishRow + 1; viewableDocuments = viewableDocuments.subList(startRow, includeFinishRowToo); } return viewableDocuments; } protected List<DocLibFileEntry> findViewableDocuments() { List<DocLibFileEntry> viewableDocuments = new ArrayList<DocLibFileEntry>(); try { long folderGroupId = dlFolder.getGroupId(); long folderId = dlFolder.getFolderId(); List<DLFileEntry> dlFileEntries = null; if (DLFolderPermission.contains( permissionChecker, folderGroupId, folderId, ActionKeys.VIEW)) { OrderByComparator orderByComparator = DocumentComparatorFactory.getComparator(getSortColumn(), isSortAscending()); dlFileEntries = DLFileEntryServiceUtil.getFileEntries( folderGroupId, folderId, QueryUtil.ALL_POS, QueryUtil.ALL_POS, orderByComparator); } if (dlFileEntries != null) { for (DLFileEntry dlFileEntry : dlFileEntries) { boolean permittedToViewDocument = false; try { permittedToViewDocument = DLFileEntryPermission.contains(permissionChecker, dlFileEntry, ActionKeys.VIEW); } catch (Exception e) { logger.error(e.getMessage(), e); } viewableDocuments.add( new DocLibFileEntry( dlFileEntry, portalURL, pathContext, folderGroupId, permittedToViewDocument)); } } } catch (Exception e) { logger.error(e.getMessage(), e); } return viewableDocuments; } @Override public Object getPrimaryKey(DocLibFileEntry docLibFileEntry) { return docLibFileEntry.getFileEntryId(); } }
/** * This class is a portlet-specific implementation of the Faces Application. Its purpose is to * override the {@link createComponent(String)} and {@link getResourceHandler()} methods so that * additional portlet-specific instances can be introduced into the Faces lifecycle. Note that * instances of this class are generated by the custom {@link ApplicationFactoryImpl}. * * @author Neil Griffin */ public class ApplicationImpl extends ApplicationWrapper { // Logger private static final Logger logger = LoggerFactory.getLogger(ApplicationImpl.class); // Private Data Members private Application wrappedApplication; private boolean wrapHandlerAtRuntime = true; public ApplicationImpl(Application application) { this.wrappedApplication = application; } /** * This method provides the ability to supply an instance of the bridge API's {@link * PortletNamingContainerUIViewRoot} class which properly handles namespacing of "id" attributes * for portlets. * * @see Application#createComponent(String) */ @Override public UIComponent createComponent(String componentType) throws FacesException { if (componentType.equals(UIViewRoot.COMPONENT_TYPE) && BridgeUtil.isPortletRequest()) { return new UIViewRootBridgeImpl(); } else { return wrappedApplication.createComponent(componentType); } } @Override public UIComponent createComponent( FacesContext facesContext, String componentType, String rendererType) { UIComponent wrappedUIComponent = wrappedApplication.createComponent(facesContext, componentType, rendererType); if (componentType.equals(DataPaginator.COMPONENT_TYPE)) { // Workaround for: http://jira.icesoft.org/browse/ICE-6398 DataPaginator dataPaginator = new DataPaginatorBridgeImpl(wrappedUIComponent); try { dataPaginator.setUIData(dataPaginator.findUIData(facesContext)); wrappedUIComponent = dataPaginator; } catch (Exception e) { logger.error(e); } } return wrappedUIComponent; } /** * The normal way of adding a {@link NavigationHandler} to a JSF application is to have a * navigation-handler element in the faces-config.xml descriptor. Unfortunately the bridge can't * use this mechanism, because it must ensure that the {@link BridgeNavigationHandler} is the * outermost instance in the chain-of-responsibility. While this could be done with * <ordering><after><others/></after></others> in the bridge's * META-INF/faces-config.xml file, the bridge must use * <ordering><before><others/></before></others> in order to * maintain compatibility with ICEfaces and other component libraries. So because of this, it is * necessary to provide this override of the {@link #getNavigationHandler()} method in order to * ensure that the {@link BridgeNavigationHandler} is the outermost instance. */ @Override public NavigationHandler getNavigationHandler() { // NOTE: Mojarra uses a servlet context listener to pre-load all the faces-config.xml files in // the classpath. // During this initialization, it will call this method override for whatever reason. But we // can't ask the // BridgeFactoryFinder to find the BridgeNavigationHandler factory at that time because it // relies on the // PortletContext object which can only be retrieved at runtime. So for this reason, we have to // delay the // wrapping the Faces default NavigationHandler until a PortletRequest happens at runtime. if (wrapHandlerAtRuntime) { FacesContext facesContext = FacesContext.getCurrentInstance(); if (facesContext != null) { try { PortletRequest portletRequest = (PortletRequest) facesContext.getExternalContext().getRequest(); if (portletRequest != null) { BridgeNavigationHandler bridgeNavigationHandler = new BridgeNavigationHandlerImpl(super.getNavigationHandler()); super.setNavigationHandler(bridgeNavigationHandler); wrapHandlerAtRuntime = false; } } catch (UnsupportedOperationException e) { // ignore -- MyFaces does not permit calling getRequest() during startup. } } } return super.getNavigationHandler(); } /** @see ApplicationWrapper#getWrapped() */ @Override public Application getWrapped() { return wrappedApplication; } }
/** @author Neil Griffin */ public class RequestHeaderValuesMap extends CaseInsensitiveHashMap<String[]> { // Private Constants private static final String CHARSET = "charset"; private static final String PARTIAL_AJAX = "partial/ajax"; // serialVersionUID private static final long serialVersionUID = 4910578014366086738L; // Logger private static final Logger logger = LoggerFactory.getLogger(RequestHeaderValuesMap.class); // Private Constants private static final String HEADER_ACCEPT = "Accept"; private static final String HEADER_ACCEPT_LANGUAGE = "Accept-Language"; private static final String HEADER_CONTENT_TYPE = "Content-Type"; private static final String HEADER_FACES_REQUEST = "Faces-Request"; public RequestHeaderValuesMap( PortletRequest portletRequest, Map<String, String> requestParameterMap) { Enumeration<String> propertyNames = portletRequest.getPropertyNames(); boolean foundAccept = false; boolean foundContentType = false; boolean foundFacesRequest = false; if (propertyNames != null) { while (propertyNames.hasMoreElements()) { boolean addHeader = true; String name = propertyNames.nextElement(); if (name.equalsIgnoreCase(HEADER_ACCEPT_LANGUAGE)) { Enumeration<Locale> locales = portletRequest.getLocales(); if (locales != null) { addHeader = false; StringBuilder buf = new StringBuilder(); for (int i = 0; locales.hasMoreElements(); i++) { if (i > 0) { buf.append(BridgeConstants.CHAR_COMMA); } Locale locale = locales.nextElement(); buf.append(locale.getLanguage()); String country = locale.getCountry(); if ((country != null) && (country.length() > 0)) { buf.append(BridgeConstants.CHAR_DASH); buf.append(country); } } super.put(name, new String[] {buf.toString()}); } } if (addHeader) { Enumeration<String> properties = portletRequest.getProperties(name); StringBuilder buf = new StringBuilder(); if (properties != null) { for (int i = 0; properties.hasMoreElements(); i++) { if (i > 0) { buf.append(BridgeConstants.CHAR_COMMA); } buf.append(properties.nextElement()); } } String values = buf.toString(); super.put(name, new String[] {values}); // NOTE: Need to check that the portlet container actually provided a value before the // bridge can // claim that it has detected "Accept", "Content-Type", or "Faces-Request". // http://issues.liferay.com/browse/FACES-34 if ((values != null) && (values.length() > 0)) { if (!foundAccept) { foundAccept = name.equalsIgnoreCase(HEADER_ACCEPT); } if (!foundContentType) { foundContentType = name.equalsIgnoreCase(HEADER_CONTENT_TYPE); } if (!foundFacesRequest) { foundFacesRequest = name.equalsIgnoreCase(HEADER_FACES_REQUEST); } } } } } if (!foundAccept) { addAcceptHeader(portletRequest); } if (!foundContentType) { addContentTypeHeader(portletRequest); } if (!foundFacesRequest) { // If this is a ResourceRequest, and the resource handler chain doesn't consider this to be a // resource, then // we assume that it's Ajax and add the "Faces-Request" header with value "partial/ajax". Note // that this is // normally done by the jsf.js JavaScript library, but in a portlet environment, the original // XmlHttpRequest // is not made available to the portlet bridge. if (portletRequest instanceof ResourceRequest) { // If the BridgeExt.FACES_AJAX_PARAMETER request parameter is "true" then set the // "partial/ajax" header // so that the Ajax-based PartialResponseWriter renders XML. Otherwise, since the URL was // probably setup // with "portlet:resource" don't setup the header because it needs to fully run the JSF // lifecycle with a // real (non-parital) ResponseWriter that renders HTML. String facesAjaxParam = requestParameterMap.get(BridgeExt.FACES_AJAX_PARAMETER); if ((facesAjaxParam != null) && BooleanHelper.isTrueToken(facesAjaxParam)) { put(HEADER_FACES_REQUEST, new String[] {PARTIAL_AJAX}); } } } } /** * Adds an "Accept" header to the hashmap, according to the response content types in the * specified request. Example Value: Accept: text/html * * @param portletRequest The current portlet request. * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1 */ protected void addAcceptHeader(PortletRequest portletRequest) { StringBuilder header = new StringBuilder(); header.append(HEADER_ACCEPT); header.append(": "); Enumeration<String> responseContentTypes = portletRequest.getResponseContentTypes(); boolean firstElement = true; while (responseContentTypes.hasMoreElements()) { if (!firstElement) { header.append(","); } String responseContentType = responseContentTypes.nextElement(); header.append(responseContentType); firstElement = false; } String acceptHeader = header.toString(); logger.debug("Adding acceptHeader=[{0}] to header map", acceptHeader); put(HEADER_ACCEPT, new String[] {header.toString()}); } /** * Adds a "Content-Type" header to the hashmap, according to the content-type and * character-encoding in the specified request. Example Value: Content-Type: text/html; * charset=ISO-8859-4 * * @param portletRequest The current portlet request. * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17 */ protected void addContentTypeHeader(PortletRequest portletRequest) { // If the specified portletRequest contains characterSetEncoding and contentType information, // then // use that to build the header. if (portletRequest instanceof ClientDataRequest) { ClientDataRequest clientDataRequest = (ClientDataRequest) portletRequest; String contentType = clientDataRequest.getContentType(); String characterSetEncoding = clientDataRequest.getCharacterEncoding(); StringBuilder header = new StringBuilder(); header.append(HEADER_CONTENT_TYPE); header.append(BridgeConstants.CHAR_COLON); header.append(BridgeConstants.CHAR_SPACE); header.append(contentType); if (characterSetEncoding != null) { header.append(BridgeConstants.CHAR_SEMICOLON); header.append(BridgeConstants.CHAR_SPACE); header.append(CHARSET); header.append(BridgeConstants.CHAR_EQUALS); header.append(characterSetEncoding); } String contentTypeHeader = header.toString(); logger.debug("Adding contentTypeHeader=[{0}] to header map", contentTypeHeader); put(HEADER_CONTENT_TYPE, new String[] {header.toString()}); } else { // TCK TestPage142: getRequestHeaderMapRenderTest } } protected void addFacesRequestPartialAjaxHeader(PortletRequest portletRequest) { // TODO: This method was stubbed-out but was never implemented? } }