View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.trinidad.context;
20  
21  import java.util.ArrayDeque;
22  import java.util.Collections;
23  import java.util.Deque;
24  import java.util.Iterator;
25  import java.util.Queue;
26  
27  import javax.faces.context.FacesContext;
28  
29  import org.apache.myfaces.trinidad.logging.TrinidadLogger;
30  
31  
32  /**
33   * Default, internal, implementation of the {@link ComponentContextManager} for use from the
34   * {@link RequestContext} class.
35   */
36  final class ComponentContextManagerImpl
37    extends ComponentContextManager
38  {
39    public void pushChange(ComponentContextChange change)
40    {
41      if (_stack == null)
42      {
43        _stack = Collections.asLifoQueue(new ArrayDeque<ComponentContextChange>());
44      }
45  
46      _stack.offer(change);
47  
48      if (_LOG.isFine())
49      {
50        _LOG.fine("Component context change pushed onto the stack. Change: {0}. New stack size: {1}",
51          new Object[] { change, _stack.size() });
52      }
53    }
54  
55    public ComponentContextChange popChange()
56      throws IllegalStateException
57    {
58      if (_stack == null)
59      {
60        throw new IllegalStateException("No changes to pop");
61      }
62  
63      ComponentContextChange change = _stack.poll();
64  
65      if (_LOG.isFine())
66      {
67        _LOG.fine("Component context change popped from the stack. Popped change: {0}. " +
68                  "New head of stack: {1}. New stack size: {2}",
69          new Object[] { change, _stack.peek(), _stack.size() });
70      }
71  
72      if (_stack.isEmpty())
73      {
74        _stack = null;
75      }
76  
77      return change;
78    }
79  
80    public ComponentContextChange peekChange()
81    {
82      return _stack == null ? null : _stack.peek();
83    }
84  
85    public SuspendedContextChanges suspend(FacesContext facesContext)
86    {
87      if (_stack == null)
88      {
89        _LOG.fine("Stack with no changes has been suspended");
90        return new SuspendedContextChangesImpl(new ArrayDeque<ComponentContextChange>(0));
91      }
92  
93      ArrayDeque<ComponentContextChange> q = new ArrayDeque<ComponentContextChange>(_stack.size());
94      for (ComponentContextChange change : _stack)
95      {
96        change.suspend(facesContext);
97        q.offer(change);
98      }
99  
100     _stack = null;
101 
102     if (_LOG.isFine())
103     {
104       _LOG.fine("Component change stack has been suspended. Number of suspended changes: {0}",
105         new Object[] { q.size() });
106     }
107 
108     return new SuspendedContextChangesImpl(q);
109   }
110 
111   public SuspendedContextChanges partialSuspend(
112     FacesContext    facesContext,
113     SuspendCallback callback)
114   {
115     if (_stack == null)
116     {
117       _LOG.fine("Stack with no changes has been partially suspended");
118       return new SuspendedContextChangesImpl(new ArrayDeque<ComponentContextChange>(0));
119     }
120 
121     ArrayDeque<ComponentContextChange> q = new ArrayDeque<ComponentContextChange>(_stack.size());
122     for (Iterator<ComponentContextChange> iter = _stack.iterator();
123          iter.hasNext(); )
124     {
125       ComponentContextChange change = iter.next();
126       SuspendCallback.SuspendResult result = callback.getSuspendResult(change);
127 
128       if (result == SuspendCallback.SuspendResult.STOP)
129       {
130         break;
131       }
132 
133       iter.remove();
134       change.suspend(facesContext);
135       q.offer(change);
136 
137       if (result == SuspendCallback.SuspendResult.STOP_AFTER_CURRENT)
138       {
139         break;
140       }
141     }
142 
143     if (_LOG.isFine())
144     {
145       _LOG.fine("Component change stack has been partially suspended. " +
146                 "Number of suspended changes: {0}. New stack size: {1}",
147         new Object[] { q.size(), _stack.size() });
148     }
149 
150     if (_stack.isEmpty())
151     {
152       _stack = null;
153     }
154 
155     return new SuspendedContextChangesImpl(q);
156   }
157 
158   public Iterator<ComponentContextChange> resume(
159     FacesContext            facesContext,
160     SuspendedContextChanges suspendedChanges)
161   {
162     assert suspendedChanges instanceof SuspendedContextChangesImpl :
163       "Invalid suspend changes";
164 
165     SuspendedContextChangesImpl suspendedChangesImpl =
166       (SuspendedContextChangesImpl)suspendedChanges;
167 
168     if (_stack == null)
169     {
170       _stack = Collections.asLifoQueue(new ArrayDeque<ComponentContextChange>());
171     }
172 
173     for (Iterator<ComponentContextChange> iter =
174            suspendedChangesImpl._suspendedStack.descendingIterator();
175          iter.hasNext(); )
176     {
177       ComponentContextChange change = iter.next();
178       change.resume(facesContext);
179       _stack.offer(change);
180     }
181 
182     if (_LOG.isFine())
183     {
184       _LOG.fine("Component change stack has been resumed. " +
185                 "Number of resumed changes: {0}. New stack size: {1}",
186         new Object[] { suspendedChangesImpl._suspendedStack.size(), _stack.size() });
187     }
188 
189     return suspendedChangesImpl._suspendedStack.descendingIterator();
190   }
191 
192   private static class SuspendedContextChangesImpl
193     extends SuspendedContextChanges
194   {
195     SuspendedContextChangesImpl(
196       Deque<ComponentContextChange> suspendedStack)
197     {
198       _suspendedStack = suspendedStack;
199     }
200 
201     private Deque<ComponentContextChange> _suspendedStack;
202   }
203 
204   private Queue<ComponentContextChange> _stack;
205 
206   private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
207                                                ComponentContextManagerImpl.class);
208 }