Search in sources :

Example 6 with ComputedValue

use of org.apache.tapestry5.plastic.ComputedValue 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)

Example 7 with ComputedValue

use of org.apache.tapestry5.plastic.ComputedValue in project tapestry-5 by apache.

the class InjectContainerWorker method createFieldValueConduitProvider.

private ComputedValue<FieldConduit<Object>> createFieldValueConduitProvider(PlasticField field) {
    final String fieldName = field.getName();
    final String fieldTypeName = field.getTypeName();
    return new ComputedValue<FieldConduit<Object>>() {

        public FieldConduit<Object> get(InstanceContext context) {
            final Class fieldType = cache.forName(fieldTypeName);
            final ComponentResources resources = context.get(ComponentResources.class);
            return new ReadOnlyComponentFieldConduit(resources, fieldName) {

                public Object get(Object instance, InstanceContext context) {
                    Component container = resources.getContainer();
                    if (!fieldType.isInstance(container)) {
                        String message = String.format("Component %s (type %s) is not assignable to field %s.%s (of type %s).", container.getComponentResources().getCompleteId(), container.getClass().getName(), resources.getComponentModel().getComponentClassName(), fieldName, fieldTypeName);
                        throw new RuntimeException(message);
                    }
                    return container;
                }
            };
        }
    };
}
Also used : Component(org.apache.tapestry5.runtime.Component) ComponentResources(org.apache.tapestry5.ComponentResources)

Example 8 with ComputedValue

use of org.apache.tapestry5.plastic.ComputedValue in project tapestry-5 by apache.

the class UnclaimedFieldWorker method createComputedFieldConduit.

private ComputedValue<FieldConduit<Object>> createComputedFieldConduit(PlasticField field) {
    final String fieldType = field.getTypeName();
    return new ComputedValue<FieldConduit<Object>>() {

        public FieldConduit<Object> get(InstanceContext context) {
            Object fieldDefaultValue = classCache.defaultValueForType(fieldType);
            InternalComponentResources resources = context.get(InternalComponentResources.class);
            return new UnclaimedFieldConduit(resources, perThreadManager.createValue(), fieldDefaultValue);
        }
    };
}
Also used : ComputedValue(org.apache.tapestry5.plastic.ComputedValue) InternalComponentResources(org.apache.tapestry5.internal.InternalComponentResources) InstanceContext(org.apache.tapestry5.plastic.InstanceContext)

Example 9 with ComputedValue

use of org.apache.tapestry5.plastic.ComputedValue in project tapestry-5 by apache.

the class CachedWorker method adviseMethod.

private void adviseMethod(PlasticClass plasticClass, PlasticMethod method) {
    // Every instance of the clas srequires its own per-thread value. This handles the case of multiple
    // pages containing the component, or the same page containing the component multiple times.
    PlasticField cacheField = plasticClass.introduceField(PerThreadValue.class, "cache$" + method.getDescription().methodName);
    cacheField.injectComputed(new ComputedValue<PerThreadValue>() {

        public PerThreadValue get(InstanceContext context) {
            // Each instance will get a new PerThreadValue
            return perThreadManager.createValue();
        }
    });
    Cached annotation = method.getAnnotation(Cached.class);
    MethodResultCacheFactory factory = createFactory(plasticClass, annotation.watch(), method);
    MethodAdvice advice = createAdvice(cacheField, factory);
    method.addAdvice(advice);
}
Also used : Cached(org.apache.tapestry5.annotations.Cached) PerThreadValue(org.apache.tapestry5.ioc.services.PerThreadValue)

Example 10 with ComputedValue

use of org.apache.tapestry5.plastic.ComputedValue in project tapestry-5 by apache.

the class InjectComponentWorker method transform.

public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model) {
    for (PlasticField field : plasticClass.getFieldsWithAnnotation(InjectComponent.class)) {
        InjectComponent annotation = field.getAnnotation(InjectComponent.class);
        field.claim(annotation);
        final String type = field.getTypeName();
        final String componentId = getComponentId(field, annotation);
        final String fieldName = field.getName();
        ComputedValue<FieldConduit<Object>> provider = new ComputedValue<FieldConduit<Object>>() {

            public FieldConduit<Object> get(InstanceContext context) {
                ComponentResources resources = context.get(ComponentResources.class);
                return new InjectedComponentFieldValueConduit(resources, fieldName, type, componentId);
            }
        };
        field.setComputedConduit(provider);
    }
}
Also used : InjectComponent(org.apache.tapestry5.annotations.InjectComponent) ComponentResources(org.apache.tapestry5.ComponentResources)

Aggregations

ComponentResources (org.apache.tapestry5.ComponentResources)5 InternalComponentResources (org.apache.tapestry5.internal.InternalComponentResources)5 TapestryException (org.apache.tapestry5.commons.internal.util.TapestryException)2 ComputedValue (org.apache.tapestry5.plastic.ComputedValue)2 InstanceContext (org.apache.tapestry5.plastic.InstanceContext)2 Asset (org.apache.tapestry5.Asset)1 Binding (org.apache.tapestry5.Binding)1 BindParameter (org.apache.tapestry5.annotations.BindParameter)1 Cached (org.apache.tapestry5.annotations.Cached)1 Environmental (org.apache.tapestry5.annotations.Environmental)1 InjectComponent (org.apache.tapestry5.annotations.InjectComponent)1 InjectContainer (org.apache.tapestry5.annotations.InjectContainer)1 Parameter (org.apache.tapestry5.annotations.Parameter)1 Path (org.apache.tapestry5.annotations.Path)1 Persist (org.apache.tapestry5.annotations.Persist)1 UnknownValueException (org.apache.tapestry5.commons.util.UnknownValueException)1 LiteralBinding (org.apache.tapestry5.internal.bindings.LiteralBinding)1 PerThreadValue (org.apache.tapestry5.ioc.services.PerThreadValue)1 Component (org.apache.tapestry5.runtime.Component)1