/*
* Copyright 2004-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.webflow.engine.model.builder;
import org.springframework.core.io.Resource;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
import org.springframework.webflow.engine.model.FlowModel;
import org.springframework.webflow.engine.model.registry.FlowModelHolder;
/**
* A flow model holder that can detect changes on an underlying flow model resource and refresh that resource
* automatically.
* <p>
* This class is thread-safe.
* <p>
* Note that this {@link FlowModel} holder uses a {@link FlowModelBuilder}.
*
* @see FlowModel
*
* @author Keith Donald
* @author Scott Andrews
*/
public class DefaultFlowModelHolder implements FlowModelHolder {
private FlowModel flowModel;
private FlowModelBuilder flowModelBuilder;
private boolean assembling;
/**
* Creates a new refreshable flow model holder that uses the configured assembler (GOF director) to drive flow
* assembly, on initial use and on any resource change or refresh.
* @param flowModelBuilder the flow model builder to use
*/
public DefaultFlowModelHolder(FlowModelBuilder flowModelBuilder) {
Assert.notNull(flowModelBuilder, "The flow model builder is required");
this.flowModelBuilder = flowModelBuilder;
}
public synchronized FlowModel getFlowModel() {
if (assembling) {
// must return early assembly result for when a flow calls itself recursively
return flowModelBuilder.getFlowModel();
}
if (flowModel == null) {
assembleFlowModel();
} else {
if (flowModelBuilder.hasFlowModelResourceChanged()) {
assembleFlowModel();
}
}
return flowModel;
}
public Resource getFlowModelResource() {
return flowModelBuilder.getFlowModelResource();
}
public boolean hasFlowModelChanged() {
return flowModelBuilder.hasFlowModelResourceChanged();
}
public synchronized void refresh() {
assembleFlowModel();
}
// internal helpers
private void assembleFlowModel() throws FlowModelBuilderException {
try {
assembling = true;
flowModelBuilder.init();
flowModelBuilder.build();
flowModel = flowModelBuilder.getFlowModel();
} finally {
try {
flowModelBuilder.dispose();
} finally {
assembling = false;
}
}
}
public String toString() {
return new ToStringCreator(this).append("flowModelBuilder", flowModelBuilder).toString();
}
}