use of org.apache.tapestry5.annotations.Mixins in project tapestry-5 by apache.
the class SaxTemplateParser method possibleTapestryComponent.
/**
* @param elementName
* @param identifiedType
* the type of the element, usually null, but may be the
* component type derived from element
*/
private void possibleTapestryComponent(TemplateParserState state, String elementName, String identifiedType) {
String id = null;
String type = identifiedType;
String mixins = null;
int count = tokenStream.getAttributeCount();
Location location = getLocation();
List<TemplateToken> attributeTokens = CollectionFactory.newList();
for (int i = 0; i < count; i++) {
QName qname = tokenStream.getAttributeName(i);
if (isXMLSpaceAttribute(qname))
continue;
// The name will be blank for an xmlns: attribute
String localName = qname.getLocalPart();
if (InternalUtils.isBlank(localName))
continue;
String uri = qname.getNamespaceURI();
String value = tokenStream.getAttributeValue(i);
Version version = NAMESPACE_URI_TO_VERSION.get(uri);
if (version != null) {
if (T_5_4.sameOrEarlier(version)) {
strictMixinParameters = true;
}
if (localName.equalsIgnoreCase(ID_ATTRIBUTE_NAME)) {
id = nullForBlank(value);
validateId(id, "Component id '%s' is not valid; component ids must be valid Java identifiers: start with a letter, and consist of letters, numbers and underscores.");
continue;
}
if (type == null && localName.equalsIgnoreCase(TYPE_ATTRIBUTE_NAME)) {
type = nullForBlank(value);
continue;
}
if (localName.equalsIgnoreCase(MIXINS_ATTRIBUTE_NAME)) {
mixins = nullForBlank(value);
continue;
}
// Anything else is the name of a Tapestry component parameter
// that is simply
// not part of the template's doctype for the element being
// instrumented.
}
attributeTokens.add(new AttributeToken(uri, localName, value, location));
}
boolean isComponent = (id != null || type != null);
if (mixins != null && !isComponent)
throw new TapestryException(String.format("You may not specify mixins for element <%s> because it does not represent a component (which requires either an id attribute or a type attribute).", elementName), location, null);
if (isComponent) {
tokenAccumulator.add(new StartComponentToken(elementName, id, type, mixins, location));
} else {
tokenAccumulator.add(new StartElementToken(tokenStream.getNamespaceURI(), elementName, location));
}
addDefineNamespaceTokens();
tokenAccumulator.addAll(attributeTokens);
if (id != null)
componentIds.put(id, location);
processBody(state.insideComponent(isComponent));
}
use of org.apache.tapestry5.annotations.Mixins in project tapestry-5 by apache.
the class TapestryAppInitializer method announceStartup.
/**
* Announce application startup, by logging (at INFO level) the names of all pages,
* components, mixins and services.
*/
public void announceStartup() {
if (// if info logging is off we can stop now
!logger.isInfoEnabled()) {
return;
}
long toFinish = System.currentTimeMillis();
SymbolSource source = registry.getService("SymbolSource", SymbolSource.class);
StringBuilder buffer = new StringBuilder("Startup status:\n\nServices:\n\n");
Formatter f = new Formatter(buffer);
int unrealized = 0;
ServiceActivityScoreboard scoreboard = registry.getService(ServiceActivityScoreboard.class);
List<ServiceActivity> serviceActivity = scoreboard.getServiceActivity();
int longest = 0;
for (ServiceActivity activity : serviceActivity) {
Status status = activity.getStatus();
longest = Math.max(longest, activity.getServiceId().length());
if (status == Status.DEFINED || status == Status.VIRTUAL)
unrealized++;
}
String formatString = "%" + longest + "s: %s\n";
for (ServiceActivity activity : serviceActivity) {
f.format(formatString, activity.getServiceId(), activity.getStatus().name());
}
f.format("\n%4.2f%% unrealized services (%d/%d)\n", 100. * unrealized / serviceActivity.size(), unrealized, serviceActivity.size());
f.format("\nApplication '%s' (version %s) startup time: %,d ms to build IoC Registry, %,d ms overall.", appName, source.valueForSymbol(TapestryHttpSymbolConstants.APPLICATION_VERSION), registryCreatedTime - startTime, toFinish - startTime);
String version = source.valueForSymbol(TapestryHttpSymbolConstants.TAPESTRY_VERSION);
boolean productionMode = Boolean.parseBoolean(source.valueForSymbol(TapestryHttpSymbolConstants.PRODUCTION_MODE));
buffer.append("\n\n");
buffer.append(" ______ __ ____\n");
buffer.append("/_ __/__ ____ ___ ___ / /_______ __ / __/\n");
buffer.append(" / / / _ `/ _ \\/ -_|_-</ __/ __/ // / /__ \\ \n");
buffer.append("/_/ \\_,_/ .__/\\__/___/\\__/_/ \\_, / /____/\n");
f.format(" /_/ /___/ %s%s\n\n", version, productionMode ? "" : " (development mode)");
// log multi-line string with OS-specific line endings (TAP5-2294)
logger.info(buffer.toString().replaceAll("\\n", System.getProperty("line.separator")));
}
use of org.apache.tapestry5.annotations.Mixins 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.annotations.Mixins in project tapestry-5 by apache.
the class ComponentAssemblerImpl method createEmbeddedAssembler.
public EmbeddedComponentAssembler createEmbeddedAssembler(String embeddedId, String componentClassName, EmbeddedComponentModel embeddedModel, String mixins, Location location) {
try {
if (InternalUtils.isBlank(componentClassName)) {
throw new TapestryException("You must specify the type via t:type, the element, or @Component annotation.", location, null);
}
EmbeddedComponentAssemblerImpl embedded = new EmbeddedComponentAssemblerImpl(assemblerSource, instantiatorSource, componentClassResolver, componentClassName, getSelector(), embeddedModel, mixins, location, strictMixinParameters);
if (embeddedIdToAssembler == null)
embeddedIdToAssembler = CollectionFactory.newMap();
embeddedIdToAssembler.put(embeddedId, embedded);
if (embeddedModel != null) {
for (String publishedParameterName : embeddedModel.getPublishedParameters()) {
if (publishedParameterToEmbeddedId == null)
publishedParameterToEmbeddedId = CollectionFactory.newCaseInsensitiveMap();
String existingEmbeddedId = publishedParameterToEmbeddedId.get(publishedParameterName);
if (existingEmbeddedId != null) {
throw new TapestryException(String.format("Parameter '%s' of embedded component '%s' can not be published as a parameter of component %s, as it has previously been published by embedded component '%s'.", publishedParameterName, embeddedId, instantiator.getModel().getComponentClassName(), existingEmbeddedId), location, null);
}
publishedParameterToEmbeddedId.put(publishedParameterName, embeddedId);
}
}
return embedded;
} catch (Exception ex) {
throw new TapestryException(String.format("Failure creating embedded component '%s' of %s: %s", embeddedId, instantiator.getModel().getComponentClassName(), ExceptionUtils.toMessage(ex)), location, ex);
}
}
use of org.apache.tapestry5.annotations.Mixins in project tapestry-5 by apache.
the class EmbeddedComponentAssemblerImpl method addMixin.
private void addMixin(String className, String... order) {
Instantiator mixinInstantiator = instantiatorSource.getInstantiator(className);
String mixinId = InternalUtils.lastTerm(className);
if (mixinIdToInstantiator.containsKey(mixinId))
throw new TapestryException(String.format("Mixins applied to a component must be unique. Mixin '%s' has already been applied.", mixinId), location, null);
mixinIdToInstantiator.put(mixinId, mixinInstantiator);
mixinsIdToOrderConstraints.put(mixinId, order);
}
Aggregations