/* * JBoss, Home of Professional Open Source * Copyright 2013, Red Hat, Inc. and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.richfaces.view.facelets.html; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import javax.faces.application.Application; import javax.faces.component.StateHolder; import javax.faces.component.behavior.ClientBehavior; import javax.faces.component.behavior.ClientBehaviorHint; import javax.faces.component.behavior.ClientBehaviorHolder; import javax.faces.context.FacesContext; /** * @author Nick Belaevski * * This class is necessary to handle nesting wrapping behaviors properly and is created to work around this issue: * https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=655 * */ // TODO - check for bug resolution public final class BehaviorStack { private static final String BEHAVIOR_STACK = "org.richfaces.BehaviorStack"; private LinkedList<BehaviorInfoImpl> behaviorStack = null; public BehaviorStack() { behaviorStack = new LinkedList<BehaviorInfoImpl>(); } public static BehaviorStack getBehaviorStack(FacesContext context, boolean createIfNull) { Map<Object, Object> attributes = context.getAttributes(); BehaviorStack behaviorStack = (BehaviorStack) attributes.get(BEHAVIOR_STACK); if (behaviorStack == null && createIfNull) { behaviorStack = new BehaviorStack(); attributes.put(BEHAVIOR_STACK, behaviorStack); } return behaviorStack; } public boolean isEmpty() { return behaviorStack.isEmpty(); } public void addBehaviors(FacesContext context, ClientBehaviorHolder behaviorHolder) { if (behaviorStack == null || behaviorStack.isEmpty()) { return; } for (BehaviorInfoImpl behaviorInfo : behaviorStack) { behaviorInfo.addBehavior(context, behaviorHolder); } } public void pushBehavior(FacesContext context, ClientBehavior clientBehavior, String behaviorId, String eventName) { Object behaviorState = ((StateHolder) clientBehavior).saveState(context); // closer behaviors are processed earlier behaviorStack.addFirst(new BehaviorInfoImpl(behaviorId, eventName, behaviorState)); } public BehaviorInfo popBehavior() { if (!behaviorStack.isEmpty()) { return behaviorStack.removeFirst(); } else { return null; } } public interface BehaviorInfo { List<ClientBehavior> getBehaviors(); } private static class BehaviorInfoImpl implements BehaviorInfo { private String behaviorId; private Object behaviorState; private String eventName; private List<ClientBehavior> behaviors; public BehaviorInfoImpl(String behaviorId, String eventName, Object behaviorState) { this.behaviorId = behaviorId; this.eventName = eventName; this.behaviorState = behaviorState; } private void addBehavior(FacesContext context, ClientBehaviorHolder behaviorHolder) { String eventName = this.eventName; if (eventName == null) { eventName = behaviorHolder.getDefaultEventName(); if (eventName == null) { return; } } if (shouldAddBehavior(behaviorHolder, eventName)) { ClientBehavior behavior = createBehavior(context); behaviorHolder.addClientBehavior(eventName, behavior); } } public List<ClientBehavior> getBehaviors() { return behaviors; } private boolean shouldAddBehavior(ClientBehaviorHolder behaviorHolder, String eventName) { if (!behaviorHolder.getEventNames().contains(eventName)) { return false; } Map<String, List<ClientBehavior>> clientBehaviorsMap = behaviorHolder.getClientBehaviors(); List<ClientBehavior> clientBehaviors = clientBehaviorsMap.get(eventName); if (clientBehaviors == null || clientBehaviors.isEmpty()) { return true; } for (ClientBehavior behavior : clientBehaviors) { Set<ClientBehaviorHint> hints = behavior.getHints(); if (hints.contains(ClientBehaviorHint.SUBMITTING)) { return false; } } return true; } private ClientBehavior createBehavior(FacesContext context) { Application application = context.getApplication(); ClientBehavior behavior = (ClientBehavior) application.createBehavior(this.behaviorId); ((StateHolder) behavior).restoreState(context, behaviorState); if (behaviors == null) { behaviors = new ArrayList<ClientBehavior>(); } behaviors.add(behavior); return behavior; } } }