use of org.apache.tapestry5.internal.InternalComponentResources in project tapestry-5 by apache.
the class BindParameterWorker method getEmbeddedComponentResourcesForPublishedParameter.
/**
* Returns the {@link InternalComponentResources} of an embeddedComponent that contains the published parameter
* publishedParameterName. This is basically a recursive search for published parameters.
*/
private InternalComponentResources getEmbeddedComponentResourcesForPublishedParameter(InternalComponentResources containerResources, String publishedParameterName) {
List<InternalComponentResources> embeddedComponentResourcesList = CollectionFactory.newList();
embeddedComponentResourcesList.add(containerResources);
while (!embeddedComponentResourcesList.isEmpty()) {
InternalComponentResources resources = embeddedComponentResourcesList.remove(0);
ComponentModel containerComponentModel = resources.getComponentModel();
for (String embeddedComponentId : containerComponentModel.getEmbeddedComponentIds()) {
EmbeddedComponentModel embeddedComponentModel = containerComponentModel.getEmbeddedComponentModel(embeddedComponentId);
InternalComponentResources embeddedComponentResources = (InternalComponentResources) resources.getEmbeddedComponent(embeddedComponentId).getComponentResources();
/**
* If the parameter is not a formal parameter, then the parameter must be a published parameter
* of an embeddedComponent of the component we are currently examining.
*/
if (embeddedComponentModel.getPublishedParameters().contains(publishedParameterName) && embeddedComponentResources.getComponentModel().isFormalParameter(publishedParameterName)) {
return embeddedComponentResources;
}
embeddedComponentResourcesList.add(embeddedComponentResources);
}
}
return null;
}
use of org.apache.tapestry5.internal.InternalComponentResources in project tapestry-5 by apache.
the class ParameterWorker method createComputedParameterConduit.
@SuppressWarnings("all")
private ComputedValue<FieldConduit<Object>> createComputedParameterConduit(final String parameterName, final String fieldTypeName, final Parameter annotation, final MethodHandle defaultMethodHandle) {
boolean primitive = PlasticUtils.isPrimitive(fieldTypeName);
final boolean allowNull = annotation.allowNull() && !primitive;
return new ComputedValue<FieldConduit<Object>>() {
public ParameterConduit get(InstanceContext context) {
final InternalComponentResources icr = context.get(InternalComponentResources.class);
final Class fieldType = classCache.forName(fieldTypeName);
final PerThreadValue<ParameterState> stateValue = perThreadManager.createValue();
return new ParameterConduit() {
// Default value for parameter, computed *once* at
// page load time.
private Object defaultValue = classCache.defaultValueForType(fieldTypeName);
private Binding parameterBinding;
boolean loaded = false;
private boolean invariant = false;
{
// Inform the ComponentResources about the parameter conduit, so it can be
// shared with mixins.
icr.setParameterConduit(parameterName, this);
icr.getPageLifecycleCallbackHub().addPageLoadedCallback(new Runnable() {
public void run() {
load();
}
});
}
private ParameterState getState() {
ParameterState state = stateValue.get();
if (state == null) {
state = new ParameterState();
state.value = defaultValue;
stateValue.set(state);
}
return state;
}
private boolean isLoaded() {
return loaded;
}
public void set(Object instance, InstanceContext context, Object newValue) {
ParameterState state = getState();
if (!loaded) {
state.value = newValue;
defaultValue = newValue;
return;
}
// This will catch read-only or unbound parameters.
writeToBinding(newValue);
state.value = newValue;
// If caching is enabled for the parameter (the typical case) and the
// component is currently rendering, then the result
// can be cached in this ParameterConduit (until the component finishes
// rendering).
state.cached = annotation.cache() && icr.isRendering();
}
private Object readFromBinding() {
Object result;
try {
Object boundValue = parameterBinding.get();
result = typeCoercer.coerce(boundValue, fieldType);
} catch (RuntimeException ex) {
throw new TapestryException(String.format("Failure reading parameter '%s' of component %s: %s", parameterName, icr.getCompleteId(), ExceptionUtils.toMessage(ex)), parameterBinding, ex);
}
if (result == null && !allowNull) {
throw new TapestryException(String.format("Parameter '%s' of component %s is bound to null. This parameter is not allowed to be null.", parameterName, icr.getCompleteId()), parameterBinding, null);
}
return result;
}
private void writeToBinding(Object newValue) {
if (parameterBinding == null) {
return;
}
try {
Object coerced = typeCoercer.coerce(newValue, parameterBinding.getBindingType());
parameterBinding.set(coerced);
} catch (RuntimeException ex) {
throw new TapestryException(String.format("Failure writing parameter '%s' of component %s: %s", parameterName, icr.getCompleteId(), ExceptionUtils.toMessage(ex)), icr, ex);
}
}
public void reset() {
if (!invariant) {
getState().reset(defaultValue);
}
}
public void load() {
if (logger.isDebugEnabled()) {
logger.debug("{} loading parameter {}", icr.getCompleteId(), parameterName);
}
if (!icr.isBound(parameterName)) {
if (logger.isDebugEnabled()) {
logger.debug("{} parameter {} not yet bound", icr.getCompleteId(), parameterName);
}
// Otherwise, construct a default binding, or use one provided from
// the component.
Binding binding = getDefaultBindingForParameter();
if (logger.isDebugEnabled()) {
logger.debug("{} parameter {} bound to default {}", icr.getCompleteId(), parameterName, binding);
}
if (binding != null) {
icr.bindParameter(parameterName, binding);
}
}
parameterBinding = icr.getBinding(parameterName);
loaded = true;
invariant = parameterBinding != null && parameterBinding.isInvariant();
getState().value = defaultValue;
}
public boolean isBound() {
return parameterBinding != null;
}
public Object get(Object instance, InstanceContext context) {
if (!isLoaded()) {
return defaultValue;
}
ParameterState state = getState();
if (state.cached || !isBound()) {
return state.value;
}
// Read the parameter's binding and cast it to the
// field's type.
Object result = readFromBinding();
if (invariant || (annotation.cache() && icr.isRendering())) {
state.value = result;
state.cached = true;
}
return result;
}
private Binding getDefaultBindingForParameter() {
if (InternalUtils.isNonBlank(annotation.value())) {
return bindingSource.newBinding("default " + parameterName, icr, annotation.defaultPrefix(), annotation.value());
}
if (annotation.autoconnect()) {
return defaultProvider.defaultBinding(parameterName, icr);
}
// Invoke the default method and install any value or Binding returned there.
invokeDefaultMethod();
return parameterBinding;
}
private void invokeDefaultMethod() {
if (defaultMethodHandle == null) {
return;
}
if (logger.isDebugEnabled()) {
logger.debug("{} invoking method {} to obtain default for parameter {}", icr.getCompleteId(), defaultMethodHandle, parameterName);
}
MethodInvocationResult result = defaultMethodHandle.invoke(icr.getComponent());
result.rethrow();
Object defaultValue = result.getReturnValue();
if (defaultValue == null) {
return;
}
if (defaultValue instanceof Binding) {
parameterBinding = (Binding) defaultValue;
return;
}
parameterBinding = new LiteralBinding(null, "default " + parameterName, defaultValue);
}
};
}
};
}
use of org.apache.tapestry5.internal.InternalComponentResources in project tapestry-5 by apache.
the class ComponentPageElementImpl method bindMixinParameter.
public void bindMixinParameter(String mixinId, String parameterName, Binding binding) {
InternalComponentResources mixinResources = NamedSet.get(mixinIdToComponentResources, mixinId);
mixinResources.bindParameter(parameterName, binding);
}
use of org.apache.tapestry5.internal.InternalComponentResources in project tapestry-5 by apache.
the class InternalComponentResourcesImplTest method add_page_lifecycle_listener.
@Test
public void add_page_lifecycle_listener() {
Component component = mockComponent();
Instantiator ins = mockInstantiator(component);
ComponentModel model = mockComponentModel();
ComponentPageElement element = mockComponentPageElement();
Page page = mockPage();
PageLifecycleListener listener = newMock(PageLifecycleListener.class);
train_getModel(ins, model);
page.addLifecycleListener(listener);
replay();
InternalComponentResources resources = new InternalComponentResourcesImpl(page, element, null, null, null, null, ins, false);
resources.addPageLifecycleListener(listener);
verify();
}
use of org.apache.tapestry5.internal.InternalComponentResources in project tapestry-5 by apache.
the class InternalComponentResourcesImplTest method post_render_cleanup_removes_all_variables.
@Test
public void post_render_cleanup_removes_all_variables() {
Component component = mockComponent();
Instantiator ins = mockInstantiator(component);
ComponentModel model = mockComponentModel();
train_getModel(ins, model);
replay();
InternalComponentResources resources = new InternalComponentResourcesImpl(null, null, null, elementResources, "Foo.bar", null, ins, false);
resources.storeRenderVariable("fred", "FRED");
resources.storeRenderVariable("barney", "BARNEY");
resources.postRenderCleanup();
try {
resources.getRenderVariable("fred");
unreachable();
} catch (IllegalArgumentException ex) {
assertEquals(ex.getMessage(), "Component Foo.bar does not contain a stored render variable with name 'fred'. Stored render variables: (none).");
}
verify();
}
Aggregations