/** * Get the state. * * <p>In JSF 2.2 it is required by the specification that the view state hidden input in each * h:form has a unique id. So we have to call this method multiple times as each h:form needs to * generate the element id for itself. * * @param stateManager the state manager. * @param origWriter the original response writer. * @return the state. * @throws IOException when an I/O error occurs. */ private StringBuilder getState(StateManager stateManager, ResponseWriter origWriter) throws IOException { FastStringWriter stateWriter = new FastStringWriter((stateManager.isSavingStateInClient(context)) ? bufSize : 128); context.setResponseWriter(origWriter.cloneWithWriter(stateWriter)); if (state == null) { state = stateManager.saveView(context); } stateManager.writeState(context, state); context.setResponseWriter(origWriter); StringBuilder stateBuilder = stateWriter.getBuffer(); return stateBuilder; }
/** * Write a properly escaped attribute name and the corresponding value. The value text will be * converted to a String if necessary. This method may only be called after a call to <code> * startElement()</code>, and before the opened element has been closed. * * @param name Attribute name to be added * @param value Attribute value to be added * @param componentPropertyName The name of the component property to which this attribute * argument applies. This argument may be <code>null</code>. * @throws IllegalStateException if this method is called when there is no currently open element * @throws IOException if an input/output error occurs * @throws NullPointerException if <code>name</code> is <code>null</code> */ public void writeAttribute(String name, Object value, String componentPropertyName) throws IOException { if (name == null) { throw new NullPointerException( MessageUtils.getExceptionMessageString( MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "name")); } if (value == null) { return; } if (isCdata) { return; } if (name.equalsIgnoreCase("src") && isScriptOrStyle()) { scriptOrStyleSrc = true; } Class valueClass = value.getClass(); // Output Boolean values specially if (valueClass == Boolean.class) { if (Boolean.TRUE.equals(value)) { // NOTE: HTML 4.01 states that boolean attributes // may legally take a single value which is the // name of the attribute itself or appear using // minimization. // http://www.w3.org/TR/html401/intro/sgmltut.html#h-3.3.4.2 attributesBuffer.write(' '); attributesBuffer.write(name); attributesBuffer.write("=\""); attributesBuffer.write(name); attributesBuffer.write('"'); } } else { attributesBuffer.write(' '); attributesBuffer.write(name); attributesBuffer.write("=\""); // write the attribute value String val = value.toString(); ensureTextBufferCapacity(val); HtmlUtils.writeAttribute( attributesBuffer, escapeUnicode, escapeIso, buffer, val, textBuffer, isScriptInAttributeValueEnabled); attributesBuffer.write('"'); } }
/** * This method automatically closes a previous element (if not already closed). * * @throws IOException if an error occurs writing */ private void closeStartIfNecessary() throws IOException { if (closeStart) { flushAttributes(); writer.write('>'); closeStart = false; if (isScriptOrStyle() && !scriptOrStyleSrc) { isXhtml = getContentType().equals(RIConstants.XHTML_CONTENT_TYPE); if (isXhtml) { if (!writingCdata) { if (isScript) { writer.write("\n//<![CDATA[\n"); } else { writer.write("\n<![CDATA[\n"); } } } else { if (isScriptHidingEnabled) { writer.write("\n<!--\n"); } } origWriter = writer; if (scriptBuffer == null) { scriptBuffer = new FastStringWriter(1024); } scriptBuffer.reset(); writer = scriptBuffer; isScript = false; isStyle = false; } } }
/** * Write a properly encoded URI attribute name and the corresponding value. The value text will be * converted to a String if necessary). This method may only be called after a call to <code> * startElement()</code>, and before the opened element has been closed. * * @param name Attribute name to be added * @param value Attribute value to be added * @param componentPropertyName The name of the component property to which this attribute * argument applies. This argument may be <code>null</code>. * @throws IllegalStateException if this method is called when there is no currently open element * @throws IOException if an input/output error occurs * @throws NullPointerException if <code>name</code> or <code>value</code> is <code>null</code> */ public void writeURIAttribute(String name, Object value, String componentPropertyName) throws IOException { if (name == null) { throw new NullPointerException( MessageUtils.getExceptionMessageString( MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "name")); } if (value == null) { throw new NullPointerException( MessageUtils.getExceptionMessageString( MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "value")); } if (isCdata) { return; } if (name.equalsIgnoreCase("src") && isScriptOrStyle()) { scriptOrStyleSrc = true; } attributesBuffer.write(' '); attributesBuffer.write(name); attributesBuffer.write("=\""); String stringValue = value.toString(); ensureTextBufferCapacity(stringValue); // Javascript URLs should not be URL-encoded if (stringValue.startsWith("javascript:")) { HtmlUtils.writeAttribute( attributesBuffer, escapeUnicode, escapeIso, buffer, stringValue, textBuffer, isScriptInAttributeValueEnabled); } else { HtmlUtils.writeURL(attributesBuffer, stringValue, textBuffer, encoding); } attributesBuffer.write('"'); }
private void flushAttributes() throws IOException { // a little complex, but the end result is, potentially, two // fewer temp objects created per call. StringBuilder b = attributesBuffer.getBuffer(); int totalLength = b.length(); if (totalLength != 0) { int curIdx = 0; while (curIdx < totalLength) { if ((totalLength - curIdx) > buffer.length) { int end = curIdx + buffer.length; b.getChars(curIdx, end, buffer, 0); writer.write(buffer); curIdx += buffer.length; } else { int len = totalLength - curIdx; b.getChars(curIdx, curIdx + len, buffer, 0); writer.write(buffer, 0, len); curIdx += len; } } attributesBuffer.reset(); } }
/** * Write directly from our FastStringWriter to the provided writer. * * @throws IOException if an error occurs */ public void flushToWriter() throws IOException { // Save the state to a new instance of StringWriter to // avoid multiple serialization steps if the view contains // multiple forms. StateManager stateManager = Util.getStateManager(context); ResponseWriter origWriter = context.getResponseWriter(); StringBuilder stateBuilder = getState(stateManager, origWriter); StringBuilder builder = fWriter.getBuffer(); // begin writing... int totalLen = builder.length(); int stateLen = stateBuilder.length(); int pos = 0; int tildeIdx = getNextDelimiterIndex(builder, pos); while (pos < totalLen) { if (tildeIdx != -1) { if (tildeIdx > pos && (tildeIdx - pos) > bufSize) { // there's enough content before the first ~ // to fill the entire buffer builder.getChars(pos, (pos + bufSize), buf, 0); orig.write(buf); pos += bufSize; } else { // write all content up to the first '~' builder.getChars(pos, tildeIdx, buf, 0); int len = (tildeIdx - pos); orig.write(buf, 0, len); // now check to see if the state saving string is // at the begining of pos, if so, write our // state out. if (builder.indexOf(RIConstants.SAVESTATE_FIELD_MARKER, pos) == tildeIdx) { // buf is effectively zero'd out at this point int statePos = 0; while (statePos < stateLen) { if ((stateLen - statePos) > bufSize) { // enough state to fill the buffer stateBuilder.getChars(statePos, (statePos + bufSize), buf, 0); orig.write(buf); statePos += bufSize; } else { int slen = (stateLen - statePos); stateBuilder.getChars(statePos, stateLen, buf, 0); orig.write(buf, 0, slen); statePos += slen; } } // push us past the last '~' at the end of the marker pos += (len + STATE_MARKER_LEN); tildeIdx = getNextDelimiterIndex(builder, pos); stateBuilder = getState(stateManager, origWriter); stateLen = stateBuilder.length(); } else { pos = tildeIdx; tildeIdx = getNextDelimiterIndex(builder, tildeIdx + 1); } } } else { // we've written all of the state field markers. // finish writing content if (totalLen - pos > bufSize) { // there's enough content to fill the buffer builder.getChars(pos, (pos + bufSize), buf, 0); orig.write(buf); pos += bufSize; } else { // we're near the end of the response builder.getChars(pos, totalLen, buf, 0); int len = (totalLen - pos); orig.write(buf, 0, len); pos += (len + 1); } } } // all state has been written. Have 'out' point to the // response so that all subsequent writes will make it to the // browser. out = orig; }