Search in sources :

Example 1 with LiteralBinding

use of org.apache.tapestry5.internal.bindings.LiteralBinding in project tapestry-5 by apache.

the class PageLoaderImpl method parameter.

private void parameter(AssemblerContext context) {
    final ParameterToken token = context.next(ParameterToken.class);
    context.add(new PageAssemblyAction() {

        public void execute(PageAssembly pageAssembly) {
            String parameterName = token.name;
            ComponentPageElement element = pageAssembly.createdElement.peek();
            Location location = token.getLocation();
            BlockImpl block = new BlockImpl(location, interner.format("Parameter %s of %s", parameterName, element.getCompleteId()));
            Binding binding = new LiteralBinding(location, "block parameter " + parameterName, block);
            EmbeddedComponentAssembler embeddedAssembler = pageAssembly.embeddedAssembler.peek();
            ParameterBinder binder = embeddedAssembler.createParameterBinder(parameterName);
            if (binder == null) {
                throw new UnknownValueException(String.format("Component %s does not include a formal parameter '%s' (and does not support informal parameters).", element.getCompleteId(), parameterName), location, null, new AvailableValues("Formal parameters", embeddedAssembler.getFormalParameterNames()));
            }
            binder.bind(pageAssembly.createdElement.peek(), binding);
            pageAssembly.bodyElement.push(block);
        }
    });
    consumeToEndElementAndPopBodyElement(context);
}
Also used : LiteralBinding(org.apache.tapestry5.internal.bindings.LiteralBinding) Binding(org.apache.tapestry5.Binding) LiteralBinding(org.apache.tapestry5.internal.bindings.LiteralBinding) UnknownValueException(org.apache.tapestry5.commons.util.UnknownValueException) AvailableValues(org.apache.tapestry5.commons.util.AvailableValues) Location(org.apache.tapestry5.commons.Location)

Example 2 with LiteralBinding

use of org.apache.tapestry5.internal.bindings.LiteralBinding 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);
                }
            };
        }
    };
}
Also used : LiteralBinding(org.apache.tapestry5.internal.bindings.LiteralBinding) Binding(org.apache.tapestry5.Binding) LiteralBinding(org.apache.tapestry5.internal.bindings.LiteralBinding) InternalComponentResources(org.apache.tapestry5.internal.InternalComponentResources) TapestryException(org.apache.tapestry5.commons.internal.util.TapestryException)

Aggregations

Binding (org.apache.tapestry5.Binding)2 LiteralBinding (org.apache.tapestry5.internal.bindings.LiteralBinding)2 Location (org.apache.tapestry5.commons.Location)1 TapestryException (org.apache.tapestry5.commons.internal.util.TapestryException)1 AvailableValues (org.apache.tapestry5.commons.util.AvailableValues)1 UnknownValueException (org.apache.tapestry5.commons.util.UnknownValueException)1 InternalComponentResources (org.apache.tapestry5.internal.InternalComponentResources)1