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