    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    }