use of org.apache.tapestry5.internal.structure.Page in project tapestry-5 by apache.
the class CachedWorker method createFactory.
private MethodResultCacheFactory createFactory(PlasticClass plasticClass, final String watch, PlasticMethod method) {
// will suffice.
if (watch.equals("")) {
return nonWatchFactory;
}
// Because of the watch, its necessary to create a factory for instances of this component and method.
final FieldHandle bindingFieldHandle = plasticClass.introduceField(Binding.class, "cache$watchBinding$" + method.getDescription().methodName).getHandle();
// Each component instance will get its own Binding instance. That handles both different locales,
// and reuse of a component (with a cached method) within a page or across pages. However, the binding can't be initialized
// until the page loads.
plasticClass.introduceInterface(PageLifecycleListener.class);
plasticClass.introduceMethod(TransformConstants.CONTAINING_PAGE_DID_LOAD_DESCRIPTION).addAdvice(new MethodAdvice() {
public void advise(MethodInvocation invocation) {
ComponentResources resources = invocation.getInstanceContext().get(ComponentResources.class);
Binding binding = bindingSource.newBinding("@Cached watch", resources, BindingConstants.PROP, watch);
bindingFieldHandle.set(invocation.getInstance(), binding);
invocation.proceed();
}
});
return new MethodResultCacheFactory() {
public MethodResultCache create(Object instance) {
Binding binding = (Binding) bindingFieldHandle.get(instance);
return new WatchedBindingMethodResultCache(binding);
}
};
}
use of org.apache.tapestry5.internal.structure.Page 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.structure.Page in project tapestry-5 by apache.
the class DefaultOpenApiDescriptionGenerator method generate.
@Override
public JSONObject generate(JSONObject documentation) {
// Making sure all pages have been loaded and transformed
for (String pageName : componentClassResolver.getPageNames()) {
try {
pageSource.getPage(pageName);
} catch (Exception e) {
// Ignoring exception, since some classes may not
// be instantiable.
LOGGER.warn(String.format("Exception while intantiating page %s for OpenAPI description generation,", pageName), e);
e.printStackTrace();
}
}
messages.set(componentMessagesSource.getApplicationCatalog(threadLocale.getLocale()));
if (documentation == null) {
documentation = new JSONObject();
}
documentation.put("openapi", symbolSource.valueForSymbol(SymbolConstants.OPENAPI_VERSION));
generateInfo(documentation);
JSONArray servers = new JSONArray();
servers.add(new JSONObject("url", baseUrlSource.getBaseURL(request.isSecure()) + // removing the last slash
basePath.substring(0, basePath.length() - 1)));
documentation.put("servers", servers);
try {
addPaths(documentation);
} catch (Exception e) {
throw new RuntimeException(e);
}
generateSchemas(documentation);
return documentation;
}
use of org.apache.tapestry5.internal.structure.Page in project tapestry-5 by apache.
the class ActivationRequestParameterWorker method decorateLinks.
@SuppressWarnings("all")
private static void decorateLinks(TransformationSupport support, String fieldName, final FieldHandle handle, final String parameterName, final ValueEncoder encoder, final URLEncoder urlEncoder) {
ComponentEventHandler handler = new ComponentEventHandler() {
public void handleEvent(Component instance, ComponentEvent event) {
Object value = handle.get(instance);
if (value == null) {
return;
}
Link link = event.getEventContext().get(Link.class, 0);
String clientValue = encoder.toClient(value);
// TAP5-1768: escape special characters
clientValue = urlEncoder.encode(clientValue);
link.addParameter(parameterName, clientValue);
}
};
support.addEventHandler(EventConstants.DECORATE_COMPONENT_EVENT_LINK, 0, String.format("ActivationRequestParameterWorker decorate component event link event handler for field %s as query parameter '%s'", fieldName, parameterName), handler);
support.addEventHandler(EventConstants.DECORATE_PAGE_RENDER_LINK, 0, String.format("ActivationRequestParameterWorker decorate page render link event handler for field %s as query parameter '%s'", fieldName, parameterName), handler);
}
use of org.apache.tapestry5.internal.structure.Page in project tapestry-5 by apache.
the class PageTesterModule method setupTestableOverrides.
@Contribute(ServiceOverride.class)
public static void setupTestableOverrides(MappedConfiguration<Class, Object> configuration, @Local TestableRequest request, @Local TestableResponse response, final ObjectLocator locator) {
configuration.add(Request.class, request);
configuration.add(Response.class, response);
TestableCookieSinkSource cookies = new TestableCookieSinkSource();
configuration.add(CookieSink.class, cookies);
configuration.add(CookieSource.class, cookies);
// With the significant changes to the handling of assets in 5.4, we introduced a problem:
// We were checking at page render time whether to generate URLs for normal or compressed
// assets and that peeked at the HttpServletRequest global, which isn't set up by PageTester.
// What we're doing here is using a hacked version of that code to force GZip support
// on.
configuration.add(ResponseCompressionAnalyzer.class, new ResponseCompressionAnalyzer() {
public boolean isGZipEnabled(ContentType contentType) {
return locator.getObject(CompressionAnalyzer.class, null).isCompressable(contentType.getMimeType());
}
public boolean isGZipSupported() {
return true;
}
});
}
Aggregations