KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > webflow > engine > builder > RefreshableFlowDefinitionHolder


1 /*
2  * Copyright 2002-2006 the original author or authors.
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 org.springframework.webflow.engine.builder;
17
18 import java.io.IOException JavaDoc;
19
20 import org.springframework.core.io.Resource;
21 import org.springframework.webflow.definition.FlowDefinition;
22 import org.springframework.webflow.definition.registry.FlowDefinitionConstructionException;
23 import org.springframework.webflow.definition.registry.FlowDefinitionHolder;
24 import org.springframework.webflow.engine.Flow;
25 import org.springframework.webflow.util.ResourceHolder;
26
27 /**
28  * A flow definition holder that can detect changes on an underlying flow
29  * definition resource and refresh that resource automatically.
30  * <p>
31  * This class is threadsafe.
32  * <p>
33  * Note that this {@link FlowDefinition} holder uses a {@link Flow} assembler.
34  * This is normal since a {@link Flow} is a {@link FlowDefinition}! This class
35  * bridges the <i>abstract</i> world of {@link FlowDefinition flow definitions}
36  * with the <i>concrete</i> world of {@link Flow flow implementations}.
37  *
38  * @see FlowDefinition
39  * @see Flow
40  * @see FlowAssembler
41  *
42  * @author Keith Donald
43  */

44 public class RefreshableFlowDefinitionHolder implements FlowDefinitionHolder {
45
46     /**
47      * The flow definition assembled by this assembler.
48      */

49     private FlowDefinition flowDefinition;
50
51     /**
52      * The flow assembler.
53      */

54     private FlowAssembler assembler;
55
56     /**
57      * A last modified date for the backing flow definition resource, used to support
58      * automatic reassembly on resource change.
59      */

60     private long lastModified;
61
62     /**
63      * A flag indicating whether or not this holder is in the middle of the
64      * assembly process.
65      */

66     private boolean assembling;
67
68     /**
69      * Creates a new refreshable flow definition holder that uses the configured
70      * assembler (GOF director) to drive flow assembly, on initial use and on any
71      * resource change or refresh.
72      * @param assembler the flow assembler to use
73      */

74     public RefreshableFlowDefinitionHolder(FlowAssembler assembler) {
75         this.assembler = assembler;
76     }
77
78     public String JavaDoc getFlowDefinitionId() {
79         return assembler.getFlowId();
80     }
81
82     public synchronized FlowDefinition getFlowDefinition() throws FlowDefinitionConstructionException {
83         if (assembling) {
84             // must return early assembly result
85
return getFlowBuilder().getFlow();
86         }
87         if (!isAssembled()) {
88             lastModified = calculateLastModified();
89             assembleFlow();
90         }
91         else {
92             refreshIfChanged();
93         }
94         return flowDefinition;
95     }
96
97     public synchronized void refresh() throws FlowBuilderException {
98         assembleFlow();
99     }
100     
101     // internal helpers
102

103     /**
104      * Returns the flow builder that actually builds the Flow definition.
105      */

106     protected FlowBuilder getFlowBuilder() {
107         return assembler.getFlowBuilder();
108     }
109
110     /**
111      * Reassemble the flow if its underlying resource has changed.
112      */

113     protected void refreshIfChanged() {
114         if (this.lastModified == -1) {
115             // just ignore, tracking last modified date not supported
116
return;
117         }
118         long calculatedLastModified = calculateLastModified();
119         if (this.lastModified < calculatedLastModified) {
120             assembleFlow();
121             this.lastModified = calculatedLastModified;
122         }
123     }
124
125     /**
126      * Helper that retrieves the last modified date by querying the backing flow
127      * resource.
128      * @return the last modified date, or -1 if it could not be retrieved
129      */

130     protected long calculateLastModified() {
131         if (getFlowBuilder() instanceof ResourceHolder) {
132             Resource resource = ((ResourceHolder)getFlowBuilder()).getResource();
133             try {
134                 return resource.getFile().lastModified();
135             }
136             catch (IOException JavaDoc e) {
137                 // ignore, last modified checks not supported
138
}
139         }
140         return -1;
141     }
142
143     /**
144      * Returns the last modifed date of the backed flow definition resource.
145      * @return the last modified date
146      */

147     protected long getLastModified() {
148         return lastModified;
149     }
150
151     /**
152      * Assemble the held flow definition, delegating to the configured
153      * FlowAssembler (director).
154      */

155     protected void assembleFlow() throws FlowBuilderException {
156         try {
157             assembling = true;
158             flowDefinition = assembler.assembleFlow();
159         }
160         finally {
161             assembling = false;
162         }
163     }
164
165     /**
166      * Returns a flag indicating if this holder has performed and completed
167      * flow definition assembly.
168      */

169     protected boolean isAssembled() {
170         return flowDefinition != null;
171     }
172
173     /**
174      * Returns a flag indicating if this holder is performing assembly.
175      */

176     protected boolean isAssembling() {
177         return assembling;
178     }
179 }
Popular Tags