View Javadoc

1   /*******************************************************************************
2    * Copyright 2013 André Rouél and Dominik Seichter
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   ******************************************************************************/
16  package net.sf.qualitytest.blueprint.configuration;
17  
18  import java.lang.reflect.Field;
19  import java.lang.reflect.Method;
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import javax.annotation.Nonnull;
24  import javax.annotation.Nullable;
25  
26  import net.sf.qualitycheck.Check;
27  import net.sf.qualitycheck.Throws;
28  import net.sf.qualitycheck.exception.IllegalEmptyArgumentException;
29  import net.sf.qualitycheck.exception.IllegalNullArgumentException;
30  import net.sf.qualitytest.blueprint.Blueprint;
31  import net.sf.qualitytest.blueprint.BlueprintConfiguration;
32  import net.sf.qualitytest.blueprint.BlueprintSession;
33  import net.sf.qualitytest.blueprint.CreationStrategy;
34  import net.sf.qualitytest.blueprint.CycleHandlingStrategy;
35  import net.sf.qualitytest.blueprint.MatchingStrategy;
36  import net.sf.qualitytest.blueprint.strategy.creation.BlueprintCreationStrategy;
37  import net.sf.qualitytest.blueprint.strategy.creation.SingleValueCreationStrategy;
38  import net.sf.qualitytest.blueprint.strategy.matching.CaseInsensitiveMethodNameMatchingStrategy;
39  import net.sf.qualitytest.blueprint.strategy.matching.TypeMatchingStrategy;
40  import net.sf.qualitytest.exception.BlueprintCycleException;
41  
42  import com.google.common.collect.ImmutableList;
43  import com.google.common.collect.Lists;
44  
45  /**
46   * Configure how blueprinting is done. A BlueprintConfiguration defines how the values for certain attributes are
47   * generated.
48   * 
49   * This class is immutable all modifier methods have to return a new instance of this class.
50   * 
51   * @author Dominik Seichter
52   */
53  class ImmutableBlueprintConfiguration implements BlueprintConfiguration {
54  
55  	/**
56  	 * Mapping of class members
57  	 */
58  	private final List<StrategyPair> mapping;
59  	private final List<CycleHandlingStrategy<?>> cycleHandling;
60  	private final boolean withPublicAttributes;
61  
62  	/**
63  	 * Create an empty {@code BlueprintConfiguration}
64  	 */
65  	public ImmutableBlueprintConfiguration() {
66  		mapping = ImmutableList.of();
67  		cycleHandling = ImmutableList.of();
68  		withPublicAttributes = false;
69  	}
70  
71  	protected ImmutableBlueprintConfiguration(@Nonnull final List<StrategyPair> attributeMapping,
72  			@Nonnull final List<CycleHandlingStrategy<?>> attributeCycleHandling, final boolean withPublicAttributes) {
73  		Check.notNull(attributeMapping, "attributeMapping");
74  		Check.notNull(attributeCycleHandling, "attributeCycleHandling");
75  
76  		mapping = ImmutableList.copyOf(attributeMapping);
77  		cycleHandling = ImmutableList.copyOf(attributeCycleHandling);
78  		this.withPublicAttributes = withPublicAttributes;
79  	}
80  
81  	@Nullable
82  	@Override
83  	@Throws(IllegalNullArgumentException.class)
84  	public <T> T construct(@Nonnull final Class<T> clazz) {
85  		return Blueprint.construct(clazz, this, new BlueprintSession());
86  	}
87  
88  	@Nullable
89  	@Override
90  	@Throws(IllegalNullArgumentException.class)
91  	public CreationStrategy<?> findCreationStrategyForField(@Nonnull final Field field) {
92  		Check.notNull(field, "field");
93  
94  		for (final StrategyPair entry : Lists.reverse(mapping)) {
95  			if (entry.getKey().matchesByField(field)) {
96  				return entry.getValue();
97  			}
98  		}
99  
100 		return null;
101 	}
102 
103 	@Nullable
104 	@Override
105 	@Throws(IllegalNullArgumentException.class)
106 	public CreationStrategy<?> findCreationStrategyForMethod(@Nonnull final Method method) {
107 		Check.notNull(method, "method");
108 
109 		for (final StrategyPair entry : Lists.reverse(mapping)) {
110 			if (entry.getKey().matchesByMethod(method)) {
111 				return entry.getValue();
112 			}
113 		}
114 
115 		return null;
116 	}
117 
118 	@Nullable
119 	@Override
120 	@Throws(IllegalNullArgumentException.class)
121 	public CreationStrategy<?> findCreationStrategyForType(@Nonnull final Class<?> clazz) {
122 		Check.notNull(clazz, "clazz");
123 
124 		for (final StrategyPair entry : Lists.reverse(mapping)) {
125 			if (entry.getKey().matchesByType(clazz)) {
126 				return entry.getValue();
127 			}
128 		}
129 
130 		return null;
131 	}
132 
133 	@SuppressWarnings("unchecked")
134 	@Override
135 	@Nullable
136 	public <T> T handleCycle(@Nonnull final BlueprintSession session, @Nonnull final Class<T> clazz) {
137 		for (final CycleHandlingStrategy<?> strategy : Lists.reverse(cycleHandling)) {
138 			if (strategy.isActiveForType(clazz)) {
139 				return (T) strategy.handleCycle(session, clazz);
140 			}
141 		}
142 
143 		throw new BlueprintCycleException(session, clazz);
144 	}
145 
146 	@Override
147 	public boolean isWithPublicAttributes() {
148 		return withPublicAttributes;
149 	}
150 
151 	@Override
152 	@Nonnull
153 	public <T> BlueprintConfiguration with(@Nonnull final Class<T> type, @Nullable final CreationStrategy<?> creator) {
154 		return with(new TypeMatchingStrategy(type), creator);
155 	}
156 
157 	@Nonnull
158 	@Override
159 	@Throws(IllegalNullArgumentException.class)
160 	public <T> BlueprintConfiguration with(@Nonnull final Class<T> type, @Nullable final T value) {
161 		return with(new TypeMatchingStrategy(type), new SingleValueCreationStrategy<T>(value));
162 	}
163 
164 	@Throws(IllegalNullArgumentException.class)
165 	@Override
166 	@Nonnull
167 	public <T> BlueprintConfiguration with(@Nonnull final CycleHandlingStrategy<T> cycleHandlingStrategy) {
168 		Check.notNull(cycleHandlingStrategy, "cycleHandlingStrategy");
169 
170 		final List<CycleHandlingStrategy<?>> strategies = new ArrayList<CycleHandlingStrategy<?>>();
171 		strategies.addAll(cycleHandling);
172 		strategies.add(cycleHandlingStrategy);
173 		return new ImmutableBlueprintConfiguration(mapping, strategies, withPublicAttributes);
174 
175 	}
176 
177 	@Nonnull
178 	@Override
179 	@Throws(IllegalNullArgumentException.class)
180 	public <T> BlueprintConfiguration with(@Nonnull final MatchingStrategy matchingStrategy) {
181 		return with(matchingStrategy, new BlueprintCreationStrategy());
182 	}
183 
184 	@Nonnull
185 	@Override
186 	@Throws(IllegalNullArgumentException.class)
187 	public BlueprintConfiguration with(@Nonnull final MatchingStrategy matcher, @Nonnull final CreationStrategy<?> creator) {
188 		Check.notNull(matcher, "matcher");
189 		Check.notNull(creator, "creator");
190 
191 		final List<StrategyPair> mapping = new ArrayList<StrategyPair>();
192 		mapping.addAll(this.mapping);
193 		mapping.add(new StrategyPair(matcher, creator));
194 		return new ImmutableBlueprintConfiguration(mapping, cycleHandling, withPublicAttributes);
195 	}
196 
197 	@Nonnull
198 	@Override
199 	@Throws({ IllegalNullArgumentException.class, IllegalEmptyArgumentException.class })
200 	public <T> BlueprintConfiguration with(@Nonnull final String name, @Nullable final T value) {
201 		Check.notEmpty(name, "name");
202 		return with(new CaseInsensitiveMethodNameMatchingStrategy(name), new SingleValueCreationStrategy<T>(value));
203 	}
204 
205 	@Nonnull
206 	@Override
207 	public BlueprintConfiguration withPublicAttributes(final boolean withPublicAttributes) {
208 		return new ImmutableBlueprintConfiguration(mapping, cycleHandling, withPublicAttributes);
209 	}
210 }