Search in sources :

Example 6 with FieldConduit

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

the class EnvironmentalWorker method transform.

private void transform(final String componentClassName, PlasticField field) {
    Environmental annotation = field.getAnnotation(Environmental.class);
    field.claim(annotation);
    final String fieldName = field.getName();
    final Class fieldType = classCache.forName(field.getTypeName());
    final boolean required = annotation.value();
    ComputedValue<FieldConduit<Object>> provider = new ComputedValue<FieldConduit<Object>>() {

        public FieldConduit<Object> get(InstanceContext context) {
            return new EnvironmentalConduit(componentClassName, fieldName, fieldType, required);
        }

        public void set(Object instance, InstanceContext context, Object newValue) {
            throw new RuntimeException(String.format("Field %s of component %s is read only.", fieldName, componentClassName));
        }
    };
    field.setComputedConduit(provider);
}
Also used : Environmental(org.apache.tapestry5.annotations.Environmental)

Example 7 with FieldConduit

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

the class ParameterWorker method convertFieldIntoParameter.

private void convertFieldIntoParameter(PlasticClass plasticClass, MutableComponentModel model, PlasticField field) {
    Parameter annotation = field.getAnnotation(Parameter.class);
    String fieldType = field.getTypeName();
    String parameterName = getParameterName(field.getName(), annotation.name());
    field.claim(annotation);
    model.addParameter(parameterName, annotation.required(), annotation.allowNull(), annotation.defaultPrefix(), annotation.cache());
    MethodHandle defaultMethodHandle = findDefaultMethodHandle(plasticClass, parameterName);
    ComputedValue<FieldConduit<Object>> computedParameterConduit = createComputedParameterConduit(parameterName, fieldType, annotation, defaultMethodHandle);
    field.setComputedConduit(computedParameterConduit);
}
Also used : Parameter(org.apache.tapestry5.annotations.Parameter)

Example 8 with FieldConduit

use of org.apache.tapestry5.plastic.FieldConduit 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 9 with FieldConduit

use of org.apache.tapestry5.plastic.FieldConduit 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 10 with FieldConduit

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

Aggregations

InternalComponentResources (org.apache.tapestry5.internal.InternalComponentResources)6 ComponentResources (org.apache.tapestry5.ComponentResources)5 TapestryException (org.apache.tapestry5.commons.internal.util.TapestryException)3 InstanceContext (org.apache.tapestry5.plastic.InstanceContext)3 PlasticField (org.apache.tapestry5.plastic.PlasticField)2 Binding (org.apache.tapestry5.Binding)1 BindParameter (org.apache.tapestry5.annotations.BindParameter)1 Environmental (org.apache.tapestry5.annotations.Environmental)1 Id (org.apache.tapestry5.annotations.Id)1 InjectComponent (org.apache.tapestry5.annotations.InjectComponent)1 InjectContainer (org.apache.tapestry5.annotations.InjectContainer)1 PageActivationContext (org.apache.tapestry5.annotations.PageActivationContext)1 Parameter (org.apache.tapestry5.annotations.Parameter)1 Persist (org.apache.tapestry5.annotations.Persist)1 UnknownValueException (org.apache.tapestry5.commons.util.UnknownValueException)1 Predicate (org.apache.tapestry5.func.Predicate)1 LiteralBinding (org.apache.tapestry5.internal.bindings.LiteralBinding)1 MethodNode (org.apache.tapestry5.internal.plastic.asm.tree.MethodNode)1 ReadOnlyComponentFieldConduit (org.apache.tapestry5.internal.transform.ReadOnlyComponentFieldConduit)1 ComputedValue (org.apache.tapestry5.plastic.ComputedValue)1