Package org.grails.web.encoder

Source Code of org.grails.web.encoder.OutputEncodingStack$OutputProxyWriter

/*
* Copyright 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.grails.web.encoder;

import java.io.IOException;
import java.io.Writer;
import java.util.Stack;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.grails.encoder.EncodedAppender;
import org.grails.encoder.EncodedAppenderFactory;
import org.grails.encoder.EncodedAppenderWriterFactory;
import org.grails.encoder.Encoder;
import org.grails.encoder.EncoderAware;
import org.grails.encoder.EncodingStateRegistry;
import org.grails.encoder.StreamingEncoder;
import org.grails.encoder.StreamingEncoderWriter;
import org.grails.web.encoder.OutputEncodingSettings;
import org.grails.web.servlet.mvc.GrailsWebRequest;
import org.grails.buffer.CodecPrintWriter;
import org.grails.buffer.GrailsLazyProxyPrintWriter;
import org.grails.buffer.GrailsLazyProxyPrintWriter.DestinationFactory;
import org.grails.buffer.GrailsWrappedWriter;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

public final class OutputEncodingStack {

    public static final Log log = LogFactory.getLog(OutputEncodingStack.class);

    private static final String ATTRIBUTE_NAME_OUTPUT_STACK="org.grails.web.encoder.OUTPUT_ENCODING_STACK";

    public static OutputEncodingStack currentStack() {
        return currentStack(true);
    }

    public static OutputEncodingStack currentStack(GrailsWebRequest request) {
        return currentStack(request, true);
    }

    public static OutputEncodingStack currentStack(boolean allowCreate) {
        return currentStack(GrailsWebRequest.lookup(), allowCreate);
    }

    public static OutputEncodingStack currentStack(GrailsWebRequest request, boolean allowCreate) {
        OutputEncodingStack outputStack = lookupStack(request);
        if (outputStack == null && allowCreate) {
            outputStack = currentStack(request, allowCreate, null, allowCreate, false);
        }
        return outputStack;
    }

    public static OutputEncodingStack currentStack(boolean allowCreate, Writer topWriter, boolean autoSync, boolean pushTop) {
        return currentStack(GrailsWebRequest.lookup(), allowCreate, topWriter, autoSync, pushTop);
    }

    public static OutputEncodingStack currentStack(GrailsWebRequest request, boolean allowCreate, Writer topWriter, boolean autoSync, boolean pushTop) {
        return currentStack(new OutputEncodingStackAttributes.Builder().webRequest(request).allowCreate(allowCreate).topWriter(topWriter).autoSync(autoSync).pushTop(pushTop).build());
    }

    public static OutputEncodingStack currentStack(OutputEncodingStackAttributes attributes) {
        OutputEncodingStack outputStack = lookupStack(attributes.getWebRequest());
        if (outputStack != null) {
            if (attributes.isPushTop()) {
                outputStack.push(attributes, false);
            }
            return outputStack;
        }

        if (attributes.isAllowCreate()) {
            return createNew(attributes);
        }

        return null;
    }

    private static final OutputEncodingStack createNew(OutputEncodingStackAttributes attributes) {
        if (attributes.getTopWriter() == null) {
            attributes=new OutputEncodingStackAttributes.Builder(attributes).topWriter(lookupRequestWriter(attributes.getWebRequest())).build();
        }
        OutputEncodingStack instance = new OutputEncodingStack(attributes);
        attributes.getWebRequest().setAttribute(
                ATTRIBUTE_NAME_OUTPUT_STACK, instance, RequestAttributes.SCOPE_REQUEST);
        return instance;
    }

    private static OutputEncodingStack lookupStack(GrailsWebRequest webRequest) {
        OutputEncodingStack outputStack = (OutputEncodingStack) webRequest.getAttribute(
                ATTRIBUTE_NAME_OUTPUT_STACK, RequestAttributes.SCOPE_REQUEST);
        return outputStack;
    }

    public static final void removeCurrentInstance() {
        RequestContextHolder.currentRequestAttributes().removeAttribute(
                ATTRIBUTE_NAME_OUTPUT_STACK, RequestAttributes.SCOPE_REQUEST);
    }

    public static final Writer currentWriter() {
        OutputEncodingStack outputStack=currentStack(false);
        if (outputStack != null) {
            return outputStack.getOutWriter();
        }

        return lookupRequestWriter();
    }

    private static Writer lookupRequestWriter() {
        GrailsWebRequest webRequest=GrailsWebRequest.lookup();
        return lookupRequestWriter(webRequest);
    }

    private static Writer lookupRequestWriter(GrailsWebRequest webRequest) {
        if (webRequest != null) {
            return webRequest.getOut();
        }
        return null;
    }

    private Stack<StackEntry> stack = new Stack<StackEntry>();
    private OutputProxyWriter taglibWriter;
    private OutputProxyWriter outWriter;
    private OutputProxyWriter staticWriter;
    private OutputProxyWriter expressionWriter;
    private boolean autoSync;
    private EncodingStateRegistry encodingStateRegistry;
    private OutputProxyWriterGroup writerGroup = new OutputProxyWriterGroup();

    private static class StackEntry implements Cloneable {
        Writer originalTarget;
        Writer unwrappedTarget;
        Encoder staticEncoder;
        Encoder taglibEncoder;
        Encoder defaultTaglibEncoder;
        Encoder outEncoder;
        Encoder expressionEncoder;

        StackEntry(Writer originalTarget, Writer unwrappedTarget) {
            this.originalTarget = originalTarget;
            this.unwrappedTarget = unwrappedTarget;
        }

        @Override
        public StackEntry clone() {
            StackEntry newEntry = new StackEntry(originalTarget, unwrappedTarget);
            newEntry.staticEncoder = staticEncoder;
            newEntry.outEncoder = outEncoder;
            newEntry.taglibEncoder = taglibEncoder;
            newEntry.defaultTaglibEncoder = defaultTaglibEncoder;
            newEntry.expressionEncoder = expressionEncoder;
            return newEntry;
        }
    }

    static class OutputProxyWriterGroup {
        OutputProxyWriter activeWriter;

        void reset() {
            activateWriter(null);
        }

        void activateWriter(OutputProxyWriter newWriter) {
            if (newWriter != activeWriter) {
                flushActive();
                activeWriter = newWriter;
            }
        }

        void flushActive() {
            if (activeWriter != null) {
                activeWriter.flush();
            }
        }
    }

    public class OutputProxyWriter extends GrailsLazyProxyPrintWriter implements EncodedAppenderFactory, EncoderAware {
        OutputProxyWriterGroup writerGroup;

        OutputProxyWriter(OutputProxyWriterGroup writerGroup, DestinationFactory factory) {
            super(factory);
            this.writerGroup = writerGroup;
        }

        public OutputEncodingStack getOutputStack() {
            return OutputEncodingStack.this;
        }

        @Override
        public Writer getOut() {
            writerGroup.activateWriter(this);
            return super.getOut();
        }

        @Override
        public EncodedAppender getEncodedAppender() {
            Writer out = getOut();
            if(out instanceof EncodedAppenderFactory) {
                return ((EncodedAppenderFactory)out).getEncodedAppender();
            } else if(out instanceof EncodedAppender) {
                return (EncodedAppender)getOut();
            } else {
                return null;
            }
        }

        @Override
        public Encoder getEncoder() {
            Writer out = getOut();
            if(out instanceof EncoderAware) {
                return ((EncoderAware)out).getEncoder();
            }
            return null;
        }
    }

    private OutputEncodingStack(OutputEncodingStackAttributes attributes) {
        outWriter = new OutputProxyWriter(writerGroup, new DestinationFactory() {
            public Writer activateDestination() throws IOException {
                StackEntry stackEntry = stack.peek();
                return createEncodingWriter(stackEntry.unwrappedTarget, stackEntry.outEncoder, encodingStateRegistry, OutputEncodingSettings.OUT_CODEC_NAME);
            }
        });
        staticWriter = new OutputProxyWriter(writerGroup, new DestinationFactory() {
            public Writer activateDestination() throws IOException {
                StackEntry stackEntry = stack.peek();
                if (stackEntry.staticEncoder == null) {
                    return stackEntry.unwrappedTarget;
                }
                return createEncodingWriter(stackEntry.unwrappedTarget, stackEntry.staticEncoder, encodingStateRegistry, OutputEncodingSettings.STATIC_CODEC_NAME);
            }
        });
        expressionWriter = new OutputProxyWriter(writerGroup, new DestinationFactory() {
            public Writer activateDestination() throws IOException {
                StackEntry stackEntry = stack.peek();
                return createEncodingWriter(stackEntry.unwrappedTarget, stackEntry.expressionEncoder, encodingStateRegistry, OutputEncodingSettings.EXPRESSION_CODEC_NAME);
            }
        });
        taglibWriter = new OutputProxyWriter(writerGroup, new DestinationFactory() {
            public Writer activateDestination() throws IOException {
                StackEntry stackEntry = stack.peek();
                return createEncodingWriter(stackEntry.unwrappedTarget, stackEntry.taglibEncoder != null ? stackEntry.taglibEncoder : stackEntry.defaultTaglibEncoder, encodingStateRegistry, OutputEncodingSettings.TAGLIB_CODEC_NAME);
            }
        });
        this.autoSync = attributes.isAutoSync();
        push(attributes, false);
        if (!autoSync) {
            applyWriterThreadLocals(outWriter);
        }
        this.encodingStateRegistry = attributes.getWebRequest().getEncodingStateRegistry();
    }

    private Writer unwrapTargetWriter(Writer targetWriter) {
        if (targetWriter instanceof GrailsWrappedWriter && ((GrailsWrappedWriter)targetWriter).isAllowUnwrappingOut()) {
            return ((GrailsWrappedWriter)targetWriter).unwrap();
        }
        return targetWriter;
    }

    public void push(final Writer newWriter) {
        push(newWriter, false);
    }

    public void push(final Writer newWriter, final boolean checkExisting) {
        OutputEncodingStackAttributes.Builder attributesBuilder=new OutputEncodingStackAttributes.Builder();
        attributesBuilder.inheritPreviousEncoders(true);
        attributesBuilder.topWriter(newWriter);
        push(attributesBuilder.build(), checkExisting);
    }

    public void push(final OutputEncodingStackAttributes attributes) {
        push(attributes, false);
    }

    public void push(final OutputEncodingStackAttributes attributes, final boolean checkExisting) {
        writerGroup.reset();

        if (checkExisting) checkExistingStack(attributes.getTopWriter());

        StackEntry previousStackEntry = null;
        if (stack.size() > 0) {
            previousStackEntry = stack.peek();
        }

        Writer topWriter = attributes.getTopWriter();
        Writer unwrappedWriter = null;
        if (topWriter!=null) {
            if (topWriter instanceof OutputProxyWriter) {
                topWriter = ((OutputProxyWriter)topWriter).getOut();
            }
            unwrappedWriter = unwrapTargetWriter(topWriter);
        } else if (previousStackEntry != null) {
            topWriter = previousStackEntry.originalTarget;
            unwrappedWriter = previousStackEntry.unwrappedTarget;
        } else {
            throw new NullPointerException("attributes.getTopWriter() is null and there is no previous stack item");
        }

        StackEntry stackEntry = new StackEntry(topWriter, unwrappedWriter);
        stackEntry.outEncoder = applyEncoder(attributes.getOutEncoder(), previousStackEntry != null ? previousStackEntry.outEncoder : null, attributes.isInheritPreviousEncoders(), attributes.isReplaceOnly());
        stackEntry.staticEncoder = applyEncoder(attributes.getStaticEncoder(), previousStackEntry != null ? previousStackEntry.staticEncoder : null, attributes.isInheritPreviousEncoders(), attributes.isReplaceOnly());
        stackEntry.expressionEncoder = applyEncoder(attributes.getExpressionEncoder(), previousStackEntry != null ? previousStackEntry.expressionEncoder : null, attributes.isInheritPreviousEncoders(), attributes.isReplaceOnly());
        stackEntry.taglibEncoder = applyEncoder(attributes.getTaglibEncoder(), previousStackEntry != null ? previousStackEntry.taglibEncoder : null, attributes.isInheritPreviousEncoders(), attributes.isReplaceOnly());
        stackEntry.defaultTaglibEncoder = applyEncoder(attributes.getDefaultTaglibEncoder(), previousStackEntry != null ? previousStackEntry.defaultTaglibEncoder : null, attributes.isInheritPreviousEncoders(), attributes.isReplaceOnly());

        stack.push(stackEntry);

        resetWriters();

        if (autoSync) {
            applyWriterThreadLocals(attributes.getTopWriter());
        }
    }

    private Encoder applyEncoder(Encoder newEncoder, Encoder previousEncoder, boolean allowInheriting, boolean replaceOnly) {
        if (newEncoder != null && (!replaceOnly || previousEncoder==null || replaceOnly && previousEncoder.isSafe())) {
            return newEncoder;
        }
        if (allowInheriting) {
            return previousEncoder;
        }
        return null;
    }

    private void checkExistingStack(final Writer topWriter) {
        if (topWriter != null) {
            for (StackEntry item : stack) {
                if (item.originalTarget == topWriter) {
                    log.warn("Pushed a writer to stack a second time. Writer type " +
                            topWriter.getClass().getName(), new Exception());
                }
            }
        }
    }

    private void resetWriters() {
        outWriter.setDestinationActivated(false);
        staticWriter.setDestinationActivated(false);
        expressionWriter.setDestinationActivated(false);
        taglibWriter.setDestinationActivated(false);
    }

    private Writer createEncodingWriter(Writer out, Encoder encoder, EncodingStateRegistry encodingStateRegistry, String codecWriterName) {
        Writer encodingWriter;
        if (out instanceof EncodedAppenderWriterFactory) {
            encodingWriter=((EncodedAppenderWriterFactory)out).getWriterForEncoder(encoder, encodingStateRegistry);
        } else if (encoder instanceof StreamingEncoder) {
            encodingWriter=new StreamingEncoderWriter(out, (StreamingEncoder)encoder, encodingStateRegistry);
        } else {
            encodingWriter=new CodecPrintWriter(out, encoder, encodingStateRegistry);
        }
        return encodingWriter;
    }

    public void pop() {
        pop(autoSync);
    }

    public void pop(boolean forceSync) {
        writerGroup.reset();
        stack.pop();
        resetWriters();
        if (stack.size() > 0) {
            StackEntry stackEntry = stack.peek();
            if (forceSync) {
                applyWriterThreadLocals(stackEntry.originalTarget);
            }
        }
    }

    public OutputProxyWriter getOutWriter() {
        return outWriter;
    }

    public OutputProxyWriter getStaticWriter() {
        return staticWriter;
    }

    public OutputProxyWriter getExpressionWriter() {
        return expressionWriter;
    }

    public OutputProxyWriter getTaglibWriter() {
        return taglibWriter;
    }

    public Encoder getOutEncoder() {
        return stack.size() > 0 ? stack.peek().outEncoder : null;
    }

    public Encoder getStaticEncoder() {
        return stack.size() > 0 ? stack.peek().staticEncoder : null;
    }

    public Encoder getExpressionEncoder() {
        return stack.size() > 0 ? stack.peek().expressionEncoder : null;
    }

    public Encoder getTaglibEncoder() {
        return stack.size() > 0 ? stack.peek().taglibEncoder : null;
    }

    public Encoder getDefaultTaglibEncoder() {
        return stack.size() > 0 ? stack.peek().defaultTaglibEncoder : null;
    }

    public Writer getCurrentOriginalWriter() {
        return stack.peek().originalTarget;
    }

    public void restoreThreadLocalsToOriginals() {
        Writer originalTopWriter = stack.firstElement().originalTarget;
        applyWriterThreadLocals(originalTopWriter);
    }

    private void applyWriterThreadLocals(Writer writer) {
        GrailsWebRequest webRequest = GrailsWebRequest.lookup();
        if (webRequest != null) {
            webRequest.setOut(writer);
        }
    }

    public void flushActiveWriter() {
        writerGroup.flushActive();
    }
}
TOP

Related Classes of org.grails.web.encoder.OutputEncodingStack$OutputProxyWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.