001: /*
002: * Copyright 2004-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.springframework.webflow.definition.registry;
017:
018: import java.util.Arrays;
019: import java.util.HashSet;
020: import java.util.Iterator;
021: import java.util.Set;
022:
023: import org.springframework.core.io.Resource;
024: import org.springframework.core.style.ToStringCreator;
025:
026: /**
027: * A flow definition registrar that populates a flow definition registry from
028: * flow definitions defined within externalized resources. Encapsulates
029: * registration behavior common to all externalized registrars and is not tied
030: * to a specific flow definition format (e.g. xml).
031: * <p>
032: * Concrete subclasses are expected to derive from this class to provide
033: * knowledge about a particular kind of definition format by implementing the
034: * abstract template methods in this class.
035: * <p>
036: * By default, when configuring the {@link #setLocations(Resource[]) locations}
037: * property, flow definitions at those locations will be assigned a registry
038: * identifier equal to the filename of the underlying definition resource, minus
039: * the filename extension. For example, a XML-based flow definition defined in
040: * the file "flow1.xml" will be identified as "flow1" when registered in a
041: * registry.
042: * <p>
043: * For full control over the assignment of flow identifiers and flow properties,
044: * configure formal
045: * {@link org.springframework.webflow.definition.registry.FlowDefinitionResource}
046: * instances using the {@link #setResources(FlowDefinitionResource[] resources)} property.
047: *
048: * @see org.springframework.webflow.definition.registry.FlowDefinitionResource
049: * @see org.springframework.webflow.definition.registry.FlowDefinitionRegistry
050: *
051: * @author Keith Donald
052: */
053: public abstract class ExternalizedFlowDefinitionRegistrar implements
054: FlowDefinitionRegistrar {
055:
056: /**
057: * File locations of externalized flow definition resources to load.
058: * A set of {@link Resource}} objects.
059: */
060: private Set locations = new HashSet();
061:
062: /**
063: * A set of formal externalized flow definitions to load.
064: * A set of {@link FlowDefinitionResource} objects.
065: */
066: private Set resources = new HashSet();
067:
068: /**
069: * Sets the locations (file paths) pointing to externalized flow
070: * definitions.
071: * <p>
072: * Flows registered from this set will be automatically assigned an id based
073: * on the filename of the flow resource.
074: * @param locations the resource locations
075: */
076: public void setLocations(Resource[] locations) {
077: this .locations = new HashSet(Arrays.asList(locations));
078: }
079:
080: /**
081: * Sets the formal set of externalized flow definitions this registrar will
082: * register.
083: * <p>
084: * Use this method when you want full control over the assigned flow id and
085: * the set of properties applied to the externalized flow resources.
086: * @param resources the externalized flow definition specifications
087: */
088: public void setResources(FlowDefinitionResource[] resources) {
089: this .resources = new HashSet(Arrays.asList(resources));
090: }
091:
092: /**
093: * Adds a flow location pointing to an externalized flow resource.
094: * <p>
095: * The flow registered from this location will automatically assigned an id
096: * based on the filename of the flow resource.
097: * @param location the definition location
098: */
099: public boolean addLocation(Resource location) {
100: return locations.add(location);
101: }
102:
103: /**
104: * Adds the flow locations pointing to externalized flow resources.
105: * <p>
106: * The flow registered from this location will automatically assigned an id
107: * based on the filename of the flow resource.
108: * @param locations the definition locations
109: */
110: public boolean addLocations(Resource[] locations) {
111: if (locations == null) {
112: return false;
113: }
114: return this .locations.addAll(Arrays.asList(locations));
115: }
116:
117: /**
118: * Adds an externalized flow definition specification pointing to an
119: * externalized flow resource.
120: * <p>
121: * Use this method when you want full control over the assigned flow id and
122: * the set of properties applied to the externalized flow resource.
123: * @param resource the definition the definition resource
124: */
125: public boolean addResource(FlowDefinitionResource resource) {
126: return resources.add(resource);
127: }
128:
129: /**
130: * Adds the externalized flow definitions pointing to externalized flow
131: * resources.
132: * <p>
133: * Use this method when you want full control over the assigned flow id and
134: * the set of properties applied to the externalized flow resources.
135: * @param resources the definitions
136: */
137: public boolean addResources(FlowDefinitionResource[] resources) {
138: if (resources == null) {
139: return false;
140: }
141: return this .resources.addAll(Arrays.asList(resources));
142: }
143:
144: public void registerFlowDefinitions(FlowDefinitionRegistry registry) {
145: processLocations(registry);
146: processResources(registry);
147: }
148:
149: // internal helpers
150:
151: /**
152: * Register the flow definitions at the configured file locations.
153: * @param registry the registry
154: */
155: private void processLocations(FlowDefinitionRegistry registry) {
156: Iterator it = locations.iterator();
157: while (it.hasNext()) {
158: Resource location = (Resource) it.next();
159: if (isFlowDefinitionResource(location)) {
160: FlowDefinitionResource resource = createFlowDefinitionResource(location);
161: register(resource, registry);
162: }
163: }
164: }
165:
166: /**
167: * Register the flow definitions at the configured file locations.
168: * @param registry the registry
169: */
170: private void processResources(FlowDefinitionRegistry registry) {
171: Iterator it = resources.iterator();
172: while (it.hasNext()) {
173: FlowDefinitionResource resource = (FlowDefinitionResource) it
174: .next();
175: register(resource, registry);
176: }
177: }
178:
179: /**
180: * Helper method to register the flow built from an externalized resource in
181: * the registry.
182: * @param resource representation of the externalized flow definition
183: * resource
184: * @param registry the flow registry to register the flow in
185: */
186: protected final void register(FlowDefinitionResource resource,
187: FlowDefinitionRegistry registry) {
188: registry
189: .registerFlowDefinition(createFlowDefinitionHolder(resource));
190: }
191:
192: // subclassing hooks
193:
194: /**
195: * Template method that calculates if the given file resource is actually a
196: * flow definition resource. Resources that aren't flow definitions will be
197: * ignored. Subclasses may override; this implementation simply returns
198: * true.
199: * @param resource the underlying resource
200: * @return true if yes, false otherwise
201: */
202: protected boolean isFlowDefinitionResource(Resource resource) {
203: return true;
204: }
205:
206: /**
207: * Factory method that creates a flow definition from an externalized
208: * resource location.
209: * @param location the location of the resource
210: * @return the externalized flow definition pointer
211: */
212: protected FlowDefinitionResource createFlowDefinitionResource(
213: Resource location) {
214: return new FlowDefinitionResource(location);
215: }
216:
217: /**
218: * Template factory method subclasses must override to return the holder for
219: * the flow definition to be registered loaded from the specified resource.
220: * @param resource the externalized resource
221: * @return the flow definition holder
222: */
223: protected abstract FlowDefinitionHolder createFlowDefinitionHolder(
224: FlowDefinitionResource resource);
225:
226: public String toString() {
227: return new ToStringCreator(this ).append("locations", locations)
228: .append("resources", resources).toString();
229: }
230: }
|