    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
    015package org.apache.tapestry5.ioc.internal;
    016
    017import org.apache.tapestry5.ioc.ObjectLocator;
    018import org.apache.tapestry5.ioc.OrderedConfiguration;
    019import org.apache.tapestry5.ioc.def.ContributionDef;
    020import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    021import org.apache.tapestry5.ioc.internal.util.Orderer;
    022
    023import 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 */
    031public 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    @Override
    061    public void add(String id, T object, String... constraints)
    062    {
    063        T coerced = object == null ? null : typeCoercer.coerce(object, expectedType);
    064
    065        // https://issues.apache.org/jira/browse/TAP5-1565
    066        // Order each added contribution after the previously added contribution
    067        // (in the same method) if no other constraint is supplied.
    068        if (constraints.length == 0 && priorId != null)
    069        {
    070            // Ugly: reassigning parameters is yuck.
    071            constraints = new String[]{"after:" + priorId};
    072        }
    073
    074        orderer.add(id, coerced, constraints);
    075
    076        priorId = id;
    077    }
    078
    079    @Override
    080    public void override(String id, T object, String... constraints)
    081    {
    082        assert InternalUtils.isNonBlank(id);
    083
    084        T coerced = object == null ? null : typeCoercer.coerce(object, expectedType);
    085
    086        OrderedConfigurationOverride<T> existing = overrides.get(id);
    087
    088        if (existing != null)
    089            throw new IllegalArgumentException(String.format("Contribution '%s' has already been overridden (by %s).",
    090                    id, existing.getContribDef()));
    091
    092        overrides.put(id, new OrderedConfigurationOverride<T>(orderer, id, coerced, constraints, contribDef));
    093    }
    094
    095    @Override
    096    public void addInstance(String id, Class<? extends T> clazz, String... constraints)
    097    {
    098        add(id, instantiate(clazz), constraints);
    099    }
    100
    101    @Override
    102    public void overrideInstance(String id, Class<? extends T> clazz, String... constraints)
    103    {
    104        override(id, instantiate(clazz), constraints);
    105    }
    106}