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 javax.faces.context;
20  
21  import java.io.IOException;
22  import java.util.Iterator;
23  import java.util.Map;
24  
25  /**
26   * @since 2.0
27   */
28  public class PartialResponseWriter extends ResponseWriterWrapper
29  {
30      public static final String RENDER_ALL_MARKER = "javax.faces.ViewRoot";
31      public static final String VIEW_STATE_MARKER = "javax.faces.ViewState";
32  
33      private ResponseWriter _wrapped;
34      private boolean hasChanges;
35      private String insertType;
36  
37     
38      /**
39       * 
40       */
41      public PartialResponseWriter(ResponseWriter writer)
42      {
43          _wrapped = writer;
44      }
45  
46      public void delete(String targetId) throws IOException
47      {
48          startChanges();
49          
50          _wrapped.startElement ("delete", null);
51          _wrapped.writeAttribute ("id", targetId, null);
52          _wrapped.endElement ("delete");
53      }
54  
55      /**
56       * {@inheritDoc}
57       */
58      @Override
59      public void endDocument() throws IOException
60      {
61          if (hasChanges)
62          {
63              // Close the <insert> element, if any.
64              //error close the last op if any
65              endInsert();
66              
67              _wrapped.endElement ("changes");
68              
69              hasChanges = false;
70          }
71          
72          _wrapped.endElement ("partial-response");
73      }
74  
75      public void endError() throws IOException
76      {
77          // Close open <error-message> element.
78          
79          _wrapped.endCDATA();
80          _wrapped.endElement ("error-message");
81          _wrapped.endElement ("error");
82      }
83  
84      public void endEval() throws IOException
85      {
86          // Close open <eval> element.
87          
88          _wrapped.endCDATA();
89          _wrapped.endElement ("eval");
90      }
91  
92      public void endExtension() throws IOException
93      {
94          _wrapped.endElement ("extension");
95      }
96  
97      public void endInsert() throws IOException
98      {
99          if (insertType == null)
100         {
101             // No insert started; ignore.
102             
103             return;
104         }
105         
106         // Close open <insert> element.
107         
108         _wrapped.endCDATA();
109         _wrapped.endElement (insertType);
110         _wrapped.endElement ("insert");
111         
112         insertType = null;
113     }
114 
115     public void endUpdate() throws IOException
116     {
117         _wrapped.endCDATA();
118         _wrapped.endElement ("update");
119     }
120 
121     /**
122      * {@inheritDoc}
123      */
124     @Override
125     public ResponseWriter getWrapped()
126     {
127         return _wrapped;
128     }
129 
130     public void redirect(String url) throws IOException
131     {
132         _wrapped.startElement ("redirect", null);
133         _wrapped.writeAttribute ("url", url, null);
134         _wrapped.endElement ("redirect");
135     }
136 
137     /**
138      * {@inheritDoc}
139      */
140     @Override
141     public void startDocument() throws IOException
142     {
143         // JSF 2.2 section 2.2.6.1 Render Response Partial Processing
144         // use writePreamble(...)
145         //_wrapped.write ("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
146         
147         _wrapped.startElement ("partial-response", null);
148         
149         // If by some reason the response has been reset, and the same
150         // PartialResponseWriter is used, it is necessary to ensure any 
151         // variable is initialized in a consistent state. To do that,
152         // the best point is when the document is started.
153         hasChanges = false;
154         insertType = null;
155     }
156 
157     public void startError(String errorName) throws IOException
158     {
159         _wrapped.startElement ("error", null);
160         
161         _wrapped.startElement ("error-name", null);
162         _wrapped.write (errorName);
163         _wrapped.endElement ("error-name");
164         
165         _wrapped.startElement ("error-message", null);
166         startCDATA();
167         
168         // Leave open; caller will write message.
169     }
170 
171     @Override
172     public void startCDATA() throws IOException
173     {
174         _wrapped.startCDATA();
175     }
176 
177     @Override
178     public void endCDATA() throws IOException
179     {
180         _wrapped.endCDATA();    
181     }
182 
183     public void startEval() throws IOException
184     {
185         startChanges();
186         
187         _wrapped.startElement ("eval", null);
188         startCDATA();
189         
190         // Leave open; caller will write statements.
191     }
192 
193     public void startExtension(Map<String, String> attributes) throws IOException
194     {
195         Iterator<String> attrNames;
196         
197         startChanges();
198         
199         _wrapped.startElement ("extension", null);
200         
201         // Write out extension attributes.
202         // TODO: schema mentions "id" attribute; not used?
203         
204         attrNames = attributes.keySet().iterator();
205         
206         while (attrNames.hasNext())
207         {
208             String attrName = attrNames.next();
209             
210             _wrapped.writeAttribute (attrName, attributes.get (attrName), null);
211         }
212         
213         // Leave open; caller will write extension elements.
214     }
215 
216     public void startInsertAfter(String targetId) throws IOException
217     {
218         startInsertCommon ("after", targetId);
219     }
220 
221     public void startInsertBefore(String targetId) throws IOException
222     {
223         startInsertCommon ("before", targetId);
224     }
225 
226     public void startUpdate(String targetId) throws IOException
227     {
228         startChanges();
229         
230         _wrapped.startElement ("update", null);
231         _wrapped.writeAttribute ("id", targetId, null);
232         startCDATA();
233         
234         // Leave open; caller will write content.
235     }
236 
237     public void updateAttributes(String targetId, Map<String, String> attributes) throws IOException
238     {
239         Iterator<String> attrNames;
240         
241         startChanges();
242         
243         _wrapped.startElement ("attributes", null);
244         _wrapped.writeAttribute ("id", targetId, null);
245         
246         attrNames = attributes.keySet().iterator();
247         
248         while (attrNames.hasNext())
249         {
250             String attrName = attrNames.next();
251             
252             _wrapped.startElement ("attribute", null);
253             _wrapped.writeAttribute ("name", attrName, null);
254             _wrapped.writeAttribute ("value", attributes.get (attrName), null);
255             _wrapped.endElement ("attribute");
256         }
257         
258         _wrapped.endElement ("attributes");
259     }
260     
261     private void startChanges () throws IOException
262     {
263         if (!hasChanges)
264         {
265             _wrapped.startElement ("changes", null);
266             
267             hasChanges = true;
268         }
269     }
270     
271     private void startInsertCommon (String type, String targetId) throws IOException
272     {
273         if (insertType != null)
274         {
275             // An insert has already been started; ignore.
276             
277             return;
278         }
279         
280         insertType = type;
281         
282         startChanges();
283         
284         _wrapped.startElement ("insert", null);
285         _wrapped.startElement (insertType, null);
286         _wrapped.writeAttribute ("id", targetId, null);
287         startCDATA();
288         
289         // Leave open; caller will write content.
290     }
291 }