001 // Copyright 2006, 2007, 2008, 2009, 2010, 2011 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.tapestry5.ioc.internal;
016
017 import org.apache.tapestry5.ioc.ObjectLocator;
018 import org.apache.tapestry5.ioc.OrderedConfiguration;
019 import org.apache.tapestry5.ioc.def.ContributionDef;
020 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
021 import org.apache.tapestry5.ioc.internal.util.Orderer;
022
023 import java.util.Map;
024
025 /**
026 * Wraps a {@link java.util.List} as a {@link org.apache.tapestry5.ioc.OrderedConfiguration}, implementing validation of
027 * values provided to an {@link org.apache.tapestry5.ioc.OrderedConfiguration}.
028 *
029 * @param <T>
030 */
031 public class ValidatingOrderedConfigurationWrapper<T> extends AbstractConfigurationImpl<T> implements
032 OrderedConfiguration<T>
033 {
034 private final TypeCoercerProxy typeCoercer;
035
036 private final Orderer<T> orderer;
037
038 private final Class<T> expectedType;
039
040 private final Map<String, OrderedConfigurationOverride<T>> overrides;
041
042 private final ContributionDef contribDef;
043
044 // Used to supply a default ordering constraint when none is supplied.
045 private String priorId;
046
047 public ValidatingOrderedConfigurationWrapper(Class<T> expectedType, ObjectLocator locator,
048 TypeCoercerProxy typeCoercer, Orderer<T> orderer, Map<String, OrderedConfigurationOverride<T>> overrides,
049 ContributionDef contribDef)
050 {
051 super(expectedType, locator);
052 this.typeCoercer = typeCoercer;
053
054 this.orderer = orderer;
055 this.overrides = overrides;
056 this.contribDef = contribDef;
057 this.expectedType = expectedType;
058 }
059
060 public void add(String id, T object, String... constraints)
061 {
062 T coerced = object == null ? null : typeCoercer.coerce(object, expectedType);
063
064 // https://issues.apache.org/jira/browse/TAP5-1565
065 // Order each added contribution after the previously added contribution
066 // (in the same method) if no other constraint is supplied.
067 if (constraints.length == 0 && priorId != null)
068 {
069 // Ugly: reassigning parameters is yuck.
070 constraints = new String[]{"after:" + priorId};
071 }
072
073 orderer.add(id, coerced, constraints);
074
075 priorId = id;
076 }
077
078 public void override(String id, T object, String... constraints)
079 {
080 assert InternalUtils.isNonBlank(id);
081
082 T coerced = object == null ? null : typeCoercer.coerce(object, expectedType);
083
084 OrderedConfigurationOverride<T> existing = overrides.get(id);
085
086 if (existing != null)
087 throw new IllegalArgumentException(String.format("Contribution '%s' has already been overridden (by %s).",
088 id, existing.getContribDef()));
089
090 overrides.put(id, new OrderedConfigurationOverride<T>(orderer, id, coerced, constraints, contribDef));
091 }
092
093 public void addInstance(String id, Class<? extends T> clazz, String... constraints)
094 {
095 add(id, instantiate(clazz), constraints);
096 }
097
098 public void overrideInstance(String id, Class<? extends T> clazz, String... constraints)
099 {
100 override(id, instantiate(clazz), constraints);
101 }
102 }