Skip to content
This repository has been archived by the owner on Sep 7, 2024. It is now read-only.

Commit

Permalink
Initial implementations for customizing OutputContext
Browse files Browse the repository at this point in the history
Introduce OutputContextCustomizer, TemplateVariableBindingCustomizer, WebOutputContextInitializer
  • Loading branch information
rainboyan committed Feb 7, 2023
1 parent f3fb758 commit c1c76a6
Show file tree
Hide file tree
Showing 12 changed files with 551 additions and 237 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2022-2023 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
*
* https://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.taglib;

/**
* Callback interface that can be used to customize a {@link AbstractTemplateVariableBinding}.
*
* @author Michael Yan
* @since 2022.0.0
* @see AbstractTemplateVariableBinding
*/
public interface TemplateVariableBindingCustomizer {

/**
* Callback to customize a {@link AbstractTemplateVariableBinding} instance.
* @param binding the Output Context to customize
*/
void customize(AbstractTemplateVariableBinding binding);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2022-2023 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
*
* https://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.taglib.encoder;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;

import org.springframework.util.Assert;

import org.grails.taglib.AbstractTemplateVariableBinding;
import org.grails.taglib.TemplateVariableBindingCustomizer;

/**
* Abstract {@link OutputContext} to support customizing
*
* @author Michael Yan
* @since 2022.0.0
* @see TemplateVariableBindingCustomizer
*/
public abstract class AbstractOutputContext implements OutputContext {

protected Set<TemplateVariableBindingCustomizer> variableBindingCustomizers = new LinkedHashSet<>();

public void addVariableBindingCustomizer(TemplateVariableBindingCustomizer... customizers) {
Assert.notNull(customizers, "Customizers must not be null");
this.variableBindingCustomizers.addAll(Arrays.asList(customizers));
}

public void setVariableBindingCustomizers(Collection<? extends TemplateVariableBindingCustomizer> customizers) {
Assert.notNull(customizers, "Customizers must not be null");
this.variableBindingCustomizers = new LinkedHashSet<>(customizers);
}

public Collection<TemplateVariableBindingCustomizer> getVariableBindingCustomizers() {
return this.variableBindingCustomizers;
}

protected void customizeTemplateVariableBinding(AbstractTemplateVariableBinding binding) {
for (TemplateVariableBindingCustomizer customizer : getVariableBindingCustomizers()) {
customizer.customize(binding);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2022-2023 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
*
* https://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.taglib.encoder;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;

import org.springframework.util.Assert;

/**
* Abstract {@link OutputContextLookup} to support customizing
*
* @author Michael Yan
* @since 2022.0.0
* @see OutputContextCustomizer
*/
public abstract class AbstractOutputContextLookup implements OutputContextLookup {

protected Set<OutputContextCustomizer> customizers = new LinkedHashSet<>();

public void addContextCustomizers(OutputContextCustomizer... customizers) {
Assert.notNull(customizers, "Customizers must not be null");
this.customizers.addAll(Arrays.asList(customizers));
}

public void setContextCustomizers(Collection<? extends OutputContextCustomizer> customizers) {
Assert.notNull(customizers, "Customizers must not be null");
this.customizers = new LinkedHashSet<>(customizers);
}

public Collection<OutputContextCustomizer> getContextCustomizers() {
return this.customizers;
}

protected void customizeOutputContext(OutputContext outputContext) {
for (OutputContextCustomizer customizer : getContextCustomizers()) {
customizer.customize(outputContext);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright 2015-2023 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
*
* https://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.taglib.encoder;

import java.io.Writer;

import grails.core.GrailsApplication;
import grails.util.Holders;

import org.grails.encoder.DefaultEncodingStateRegistry;
import org.grails.encoder.EncodingStateRegistry;
import org.grails.taglib.AbstractTemplateVariableBinding;
import org.grails.taglib.TemplateVariableBinding;

/**
* Default implementation for {@link OutputContext}
*
* @author Lari Hotari
* @since 3.0
*/
public class DefaultOutputContext extends AbstractOutputContext {

private OutputEncodingStack outputEncodingStack;

private Writer currentWriter;

private AbstractTemplateVariableBinding binding;

private EncodingStateRegistry encodingStateRegistry = new DefaultEncodingStateRegistry();

public DefaultOutputContext() {

}

@Override
public EncodingStateRegistry getEncodingStateRegistry() {
return this.encodingStateRegistry;
}

@Override
public void setCurrentOutputEncodingStack(OutputEncodingStack outputEncodingStack) {
this.outputEncodingStack = outputEncodingStack;
}

@Override
public OutputEncodingStack getCurrentOutputEncodingStack() {
return this.outputEncodingStack;
}

@Override
public Writer getCurrentWriter() {
return this.currentWriter;
}

@Override
public void setCurrentWriter(Writer currentWriter) {
this.currentWriter = currentWriter;
}

@Override
public AbstractTemplateVariableBinding createAndRegisterRootBinding() {
this.binding = new TemplateVariableBinding();
customizeTemplateVariableBinding(this.binding);
return this.binding;
}

@Override
public AbstractTemplateVariableBinding getBinding() {
return this.binding;
}

@Override
public void setBinding(AbstractTemplateVariableBinding binding) {
this.binding = binding;
}

@Override
public GrailsApplication getGrailsApplication() {
return Holders.findApplication();
}

@Override
public void setContentType(String contentType) {
// no-op
}

@Override
public boolean isContentTypeAlreadySet() {
return true;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2022 the original author or authors.
* Copyright 2015-2023 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.
Expand All @@ -15,21 +15,19 @@
*/
package org.grails.taglib.encoder;

import java.io.Writer;

import org.springframework.core.Ordered;

import grails.core.GrailsApplication;
import grails.util.Holders;

import org.grails.encoder.DefaultEncodingStateRegistry;
import org.grails.encoder.EncodingStateRegistry;
import org.grails.encoder.EncodingStateRegistryLookup;
import org.grails.encoder.EncodingStateRegistryLookupHolder;
import org.grails.taglib.AbstractTemplateVariableBinding;
import org.grails.taglib.TemplateVariableBinding;

public class DefaultOutputContextLookup implements OutputContextLookup, EncodingStateRegistryLookup, Ordered {
/**
* Default implementation for {@link OutputContextLookup}
*
* @author Lari Hotari
* @since 3.0
*/
public class DefaultOutputContextLookup extends AbstractOutputContextLookup implements EncodingStateRegistryLookup, Ordered {

private ThreadLocal<OutputContext> outputContextThreadLocal = new ThreadLocal<OutputContext>() {
@Override
Expand All @@ -38,13 +36,19 @@ protected OutputContext initialValue() {
}
};

public DefaultOutputContextLookup() {

}

@Override
public OutputContext lookupOutputContext() {
if (EncodingStateRegistryLookupHolder.getEncodingStateRegistryLookup() == null) {
// TODO: improve EncodingStateRegistry solution so that global state doesn't have to be used
EncodingStateRegistryLookupHolder.setEncodingStateRegistryLookup(this);
}
return this.outputContextThreadLocal.get();
OutputContext outputContext = this.outputContextThreadLocal.get();
customizeOutputContext(outputContext);
return outputContext;
}

@Override
Expand All @@ -57,80 +61,4 @@ public EncodingStateRegistry lookup() {
return lookupOutputContext().getEncodingStateRegistry();
}

public DefaultOutputContextLookup() {

}

public static class DefaultOutputContext implements OutputContext {

private OutputEncodingStack outputEncodingStack;

private Writer currentWriter;

private AbstractTemplateVariableBinding binding;

private EncodingStateRegistry encodingStateRegistry = new DefaultEncodingStateRegistry();

public DefaultOutputContext() {

}

@Override
public EncodingStateRegistry getEncodingStateRegistry() {
return this.encodingStateRegistry;
}

@Override
public void setCurrentOutputEncodingStack(OutputEncodingStack outputEncodingStack) {
this.outputEncodingStack = outputEncodingStack;
}

@Override
public OutputEncodingStack getCurrentOutputEncodingStack() {
return this.outputEncodingStack;
}

@Override
public Writer getCurrentWriter() {
return this.currentWriter;
}

@Override
public void setCurrentWriter(Writer currentWriter) {
this.currentWriter = currentWriter;
}

@Override
public AbstractTemplateVariableBinding createAndRegisterRootBinding() {
this.binding = new TemplateVariableBinding();
return this.binding;
}

@Override
public AbstractTemplateVariableBinding getBinding() {
return this.binding;
}

@Override
public void setBinding(AbstractTemplateVariableBinding binding) {
this.binding = binding;
}

@Override
public GrailsApplication getGrailsApplication() {
return Holders.findApplication();
}

@Override
public void setContentType(String contentType) {
// no-op
}

@Override
public boolean isContentTypeAlreadySet() {
return true;
}

}

}
Loading

0 comments on commit c1c76a6

Please sign in to comment.