| // Copyright 2006, 2007, 2008 The Apache Software Foundation |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package org.apache.tapestry5.internal.model; |
| |
| import org.apache.tapestry5.ioc.Location; |
| import org.apache.tapestry5.ioc.Resource; |
| import org.apache.tapestry5.ioc.internal.util.CollectionFactory; |
| import org.apache.tapestry5.ioc.internal.util.Defense; |
| import org.apache.tapestry5.ioc.internal.util.IdAllocator; |
| import org.apache.tapestry5.ioc.internal.util.InternalUtils; |
| import org.apache.tapestry5.model.*; |
| import org.slf4j.Logger; |
| |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Internal implementation of {@link org.apache.tapestry5.model.MutableComponentModel}. |
| */ |
| public final class MutableComponentModelImpl implements MutableComponentModel |
| { |
| private final ComponentModel parentModel; |
| |
| private final Resource baseResource; |
| |
| private final String componentClassName; |
| |
| private final IdAllocator persistentFieldNameAllocator = new IdAllocator(); |
| |
| private final Logger logger; |
| |
| private Map<String, ParameterModel> parameters; |
| |
| private Map<String, EmbeddedComponentModel> embeddedComponents; |
| |
| /** |
| * Maps from field name to strategy. |
| */ |
| private Map<String, String> persistentFields; |
| |
| private List<String> mixinClassNames; |
| |
| private boolean informalParametersSupported; |
| |
| private boolean mixinAfter; |
| |
| private Map<String, String> metaData; |
| |
| public MutableComponentModelImpl(String componentClassName, Logger logger, Resource baseResource, |
| ComponentModel parentModel) |
| { |
| this.componentClassName = componentClassName; |
| this.logger = logger; |
| this.baseResource = baseResource; |
| this.parentModel = parentModel; |
| |
| // Pre-allocate names from the parent, to avoid name collisions. |
| |
| if (this.parentModel != null) |
| { |
| for (String name : this.parentModel.getPersistentFieldNames()) |
| { |
| persistentFieldNameAllocator.allocateId(name); |
| } |
| } |
| } |
| |
| @Override |
| public String toString() |
| { |
| return String.format("ComponentModel[%s]", componentClassName); |
| } |
| |
| public Logger getLogger() |
| { |
| return logger; |
| } |
| |
| public Resource getBaseResource() |
| { |
| return baseResource; |
| } |
| |
| public String getComponentClassName() |
| { |
| return componentClassName; |
| } |
| |
| public void addParameter(String name, boolean required, String defaultBindingPrefix) |
| { |
| Defense.notBlank(name, "name"); |
| Defense.notBlank(defaultBindingPrefix, "defaultBindingPrefix"); |
| |
| // TODO: Check for conflict with base model |
| |
| if (parameters == null) parameters = CollectionFactory.newCaseInsensitiveMap(); |
| else |
| { |
| if (parameters.containsKey(name)) |
| throw new IllegalArgumentException(ModelMessages.duplicateParameter(name, componentClassName)); |
| } |
| |
| parameters.put(name, new ParameterModelImpl(name, required, defaultBindingPrefix)); |
| } |
| |
| public ParameterModel getParameterModel(String parameterName) |
| { |
| ParameterModel result = InternalUtils.get(parameters, parameterName.toLowerCase()); |
| |
| if (result == null && parentModel != null) result = parentModel.getParameterModel(parameterName); |
| |
| return result; |
| } |
| |
| public List<String> getParameterNames() |
| { |
| List<String> names = CollectionFactory.newList(); |
| |
| if (parameters != null) names.addAll(parameters.keySet()); |
| |
| if (parentModel != null) names.addAll(parentModel.getParameterNames()); |
| |
| Collections.sort(names); |
| |
| return names; |
| } |
| |
| public List<String> getDeclaredParameterNames() |
| { |
| return InternalUtils.sortedKeys(parameters); |
| } |
| |
| public MutableEmbeddedComponentModel addEmbeddedComponent(String id, String type, String componentClassName, |
| boolean inheritInformalParameters, Location location) |
| { |
| // TODO: Parent compent model? Or would we simply override the parent? |
| |
| if (embeddedComponents == null) embeddedComponents = CollectionFactory.newCaseInsensitiveMap(); |
| else if (embeddedComponents.containsKey(id)) |
| throw new IllegalArgumentException(ModelMessages.duplicateComponentId(id, this.componentClassName)); |
| |
| MutableEmbeddedComponentModel embedded = new MutableEmbeddedComponentModelImpl(id, type, componentClassName, |
| this.componentClassName, |
| inheritInformalParameters, |
| location); |
| |
| embeddedComponents.put(id, embedded); |
| |
| return embedded; // So that parameters can be filled in |
| } |
| |
| public List<String> getEmbeddedComponentIds() |
| { |
| List<String> result = CollectionFactory.newList(); |
| |
| if (embeddedComponents != null) result.addAll(embeddedComponents.keySet()); |
| |
| if (parentModel != null) result.addAll(parentModel.getEmbeddedComponentIds()); |
| |
| Collections.sort(result); |
| |
| return result; |
| } |
| |
| public EmbeddedComponentModel getEmbeddedComponentModel(String componentId) |
| { |
| EmbeddedComponentModel result = InternalUtils.get(embeddedComponents, componentId); |
| |
| if (result == null && parentModel != null) result = parentModel.getEmbeddedComponentModel(componentId); |
| |
| return result; |
| } |
| |
| public String getFieldPersistenceStrategy(String fieldName) |
| { |
| String result = InternalUtils.get(persistentFields, fieldName); |
| |
| if (result == null && parentModel != null) result = parentModel.getFieldPersistenceStrategy(fieldName); |
| |
| if (result == null) throw new IllegalArgumentException(ModelMessages.missingPersistentField(fieldName)); |
| |
| return result; |
| } |
| |
| public List<String> getPersistentFieldNames() |
| { |
| return persistentFieldNameAllocator.getAllocatedIds(); |
| } |
| |
| public String setFieldPersistenceStrategy(String fieldName, String strategy) |
| { |
| String logicalFieldName = persistentFieldNameAllocator.allocateId(fieldName); |
| |
| if (persistentFields == null) persistentFields = CollectionFactory.newMap(); |
| |
| persistentFields.put(logicalFieldName, strategy); |
| |
| return logicalFieldName; |
| } |
| |
| public boolean isRootClass() |
| { |
| return parentModel == null; |
| } |
| |
| public void addMixinClassName(String mixinClassName) |
| { |
| if (mixinClassNames == null) mixinClassNames = CollectionFactory.newList(); |
| |
| mixinClassNames.add(mixinClassName); |
| } |
| |
| public List<String> getMixinClassNames() |
| { |
| List<String> result = CollectionFactory.newList(); |
| |
| if (mixinClassNames != null) result.addAll(mixinClassNames); |
| |
| if (parentModel != null) result.addAll(parentModel.getMixinClassNames()); |
| |
| Collections.sort(result); |
| |
| return result; |
| } |
| |
| public void enableSupportsInformalParameters() |
| { |
| informalParametersSupported = true; |
| } |
| |
| public boolean getSupportsInformalParameters() |
| { |
| return informalParametersSupported; |
| } |
| |
| public ComponentModel getParentModel() |
| { |
| return parentModel; |
| } |
| |
| public boolean isMixinAfter() |
| { |
| return mixinAfter; |
| } |
| |
| public void setMixinAfter(boolean mixinAfter) |
| { |
| this.mixinAfter = mixinAfter; |
| } |
| |
| public void setMeta(String key, String value) |
| { |
| Defense.notBlank(key, "key"); |
| Defense.notBlank(value, "value"); |
| |
| if (metaData == null) metaData = CollectionFactory.newCaseInsensitiveMap(); |
| |
| // TODO: Error if duplicate? |
| |
| metaData.put(key, value); |
| } |
| |
| public String getMeta(String key) |
| { |
| String result = InternalUtils.get(metaData, key); |
| |
| if (result == null && parentModel != null) result = parentModel.getMeta(key); |
| |
| return result; |
| } |
| |
| } |