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 }