001: // Copyright 2006, 2007 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.tapestry.internal.model;
016:
017: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
018: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
019: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
020: import static org.apache.tapestry.ioc.internal.util.Defense.notBlank;
021:
022: import java.util.Collections;
023: import java.util.List;
024: import java.util.Map;
025:
026: import org.apache.commons.logging.Log;
027: import org.apache.tapestry.ioc.Location;
028: import org.apache.tapestry.ioc.Resource;
029: import org.apache.tapestry.ioc.internal.util.IdAllocator;
030: import org.apache.tapestry.ioc.internal.util.InternalUtils;
031: import org.apache.tapestry.model.ComponentModel;
032: import org.apache.tapestry.model.EmbeddedComponentModel;
033: import org.apache.tapestry.model.MutableComponentModel;
034: import org.apache.tapestry.model.MutableEmbeddedComponentModel;
035: import org.apache.tapestry.model.ParameterModel;
036:
037: /**
038: * Internal implementation of {@link org.apache.tapestry.model.MutableComponentModel}.
039: */
040: public final class MutableComponentModelImpl implements
041: MutableComponentModel {
042: private final ComponentModel _parentModel;
043:
044: private final Resource _baseResource;
045:
046: private final String _componentClassName;
047:
048: private final IdAllocator _persistentFieldNameAllocator = new IdAllocator();
049:
050: private final Log _log;
051:
052: private Map<String, ParameterModel> _parameters;
053:
054: private Map<String, EmbeddedComponentModel> _embeddedComponents;
055:
056: /** Maps from field name to strategy. */
057: private Map<String, String> _persistentFields;
058:
059: private List<String> _mixinClassNames;
060:
061: private boolean _informalParametersSupported;
062:
063: private boolean _mixinAfter;
064:
065: private Map<String, String> _metaData;
066:
067: public MutableComponentModelImpl(String componentClassName,
068: Log log, Resource baseResource, ComponentModel parentModel) {
069: _componentClassName = componentClassName;
070: _log = log;
071: _baseResource = baseResource;
072: _parentModel = parentModel;
073:
074: // Pre-allocate names from the parent, to avoid name collisions.
075:
076: if (_parentModel != null) {
077: for (String name : _parentModel.getPersistentFieldNames()) {
078: _persistentFieldNameAllocator.allocateId(name);
079: }
080: }
081: }
082:
083: @Override
084: public String toString() {
085: return String.format("ComponentModel[%s]", _componentClassName);
086: }
087:
088: public Log getLog() {
089: return _log;
090: }
091:
092: public Resource getBaseResource() {
093: return _baseResource;
094: }
095:
096: public String getComponentClassName() {
097: return _componentClassName;
098: }
099:
100: public void addParameter(String name, boolean required,
101: String defaultBindingPrefix) {
102: notBlank(name, "name");
103: notBlank(defaultBindingPrefix, "defaultBindingPrefix");
104:
105: // TODO: Check for conflict with base model
106:
107: if (_parameters == null)
108: _parameters = newCaseInsensitiveMap();
109: else {
110: if (_parameters.containsKey(name))
111: throw new IllegalArgumentException(ModelMessages
112: .duplicateParameter(name, _componentClassName));
113: }
114:
115: _parameters.put(name, new ParameterModelImpl(name, required,
116: defaultBindingPrefix));
117: }
118:
119: public ParameterModel getParameterModel(String parameterName) {
120: ParameterModel result = InternalUtils.get(_parameters,
121: parameterName.toLowerCase());
122:
123: if (result == null && _parentModel != null)
124: result = _parentModel.getParameterModel(parameterName);
125:
126: return result;
127: }
128:
129: public List<String> getParameterNames() {
130: List<String> names = newList();
131:
132: if (_parameters != null)
133: names.addAll(_parameters.keySet());
134:
135: if (_parentModel != null)
136: names.addAll(_parentModel.getParameterNames());
137:
138: Collections.sort(names);
139:
140: return names;
141: }
142:
143: public List<String> getDeclaredParameterNames() {
144: return InternalUtils.sortedKeys(_parameters);
145: }
146:
147: public MutableEmbeddedComponentModel addEmbeddedComponent(
148: String id, String type, String componentClassName,
149: Location location) {
150: // TODO: Parent compent model? Or would we simply override the parent?
151:
152: if (_embeddedComponents == null)
153: _embeddedComponents = newCaseInsensitiveMap();
154: else if (_embeddedComponents.containsKey(id))
155: throw new IllegalArgumentException(ModelMessages
156: .duplicateComponentId(id, _componentClassName));
157:
158: MutableEmbeddedComponentModel embedded = new MutableEmbeddedComponentModelImpl(
159: id, type, componentClassName, _componentClassName,
160: location);
161:
162: _embeddedComponents.put(id, embedded);
163:
164: return embedded; // So that parameters can be filled in
165: }
166:
167: public List<String> getEmbeddedComponentIds() {
168: List<String> result = newList();
169:
170: if (_embeddedComponents != null)
171: result.addAll(_embeddedComponents.keySet());
172:
173: if (_parentModel != null)
174: result.addAll(_parentModel.getEmbeddedComponentIds());
175:
176: Collections.sort(result);
177:
178: return result;
179: }
180:
181: public EmbeddedComponentModel getEmbeddedComponentModel(
182: String componentId) {
183: EmbeddedComponentModel result = InternalUtils.get(
184: _embeddedComponents, componentId);
185:
186: if (result == null && _parentModel != null)
187: result = _parentModel
188: .getEmbeddedComponentModel(componentId);
189:
190: return result;
191: }
192:
193: public String getFieldPersistenceStrategy(String fieldName) {
194: String result = InternalUtils.get(_persistentFields, fieldName);
195:
196: if (result == null && _parentModel != null)
197: result = _parentModel
198: .getFieldPersistenceStrategy(fieldName);
199:
200: if (result == null)
201: throw new IllegalArgumentException(ModelMessages
202: .missingPersistentField(fieldName));
203:
204: return result;
205: }
206:
207: public List<String> getPersistentFieldNames() {
208: return _persistentFieldNameAllocator.getAllocatedIds();
209: }
210:
211: public String setFieldPersistenceStrategy(String fieldName,
212: String strategy) {
213: String stripped = InternalUtils.stripMemberPrefix(fieldName);
214:
215: String logicalFieldName = _persistentFieldNameAllocator
216: .allocateId(stripped);
217:
218: if (_persistentFields == null)
219: _persistentFields = newMap();
220:
221: _persistentFields.put(logicalFieldName, strategy);
222:
223: return logicalFieldName;
224: }
225:
226: public boolean isRootClass() {
227: return _parentModel == null;
228: }
229:
230: public void addMixinClassName(String mixinClassName) {
231: if (_mixinClassNames == null)
232: _mixinClassNames = newList();
233:
234: _mixinClassNames.add(mixinClassName);
235: }
236:
237: public List<String> getMixinClassNames() {
238: List<String> result = newList();
239:
240: if (_mixinClassNames != null)
241: result.addAll(_mixinClassNames);
242:
243: if (_parentModel != null)
244: result.addAll(_parentModel.getMixinClassNames());
245:
246: Collections.sort(result);
247:
248: return result;
249: }
250:
251: public void enableSupportsInformalParameters() {
252: _informalParametersSupported = true;
253: }
254:
255: public boolean getSupportsInformalParameters() {
256: return _informalParametersSupported;
257: }
258:
259: public ComponentModel getParentModel() {
260: return _parentModel;
261: }
262:
263: public boolean isMixinAfter() {
264: return _mixinAfter;
265: }
266:
267: public void setMixinAfter(boolean mixinAfter) {
268: _mixinAfter = mixinAfter;
269: }
270:
271: public void setMeta(String key, String value) {
272: notBlank(key, "key");
273: notBlank(value, "value");
274:
275: if (_metaData == null)
276: _metaData = newCaseInsensitiveMap();
277:
278: // TODO: Error if duplicate?
279:
280: _metaData.put(key, value);
281: }
282:
283: public String getMeta(String key) {
284: String result = InternalUtils.get(_metaData, key);
285:
286: if (result == null && _parentModel != null)
287: result = _parentModel.getMeta(key);
288:
289: return result;
290: }
291:
292: }
|