Package org.springframework.webflow.config

Source Code of org.springframework.webflow.config.FlowRegistryFactoryBean

/*
* Copyright 2004-2012 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.config;

import java.io.IOException;
import java.util.Collections;
import java.util.Set;

import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.binding.convert.ConversionExecutor;
import org.springframework.core.io.Resource;
import org.springframework.util.ClassUtils;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.definition.FlowDefinition;
import org.springframework.webflow.definition.registry.FlowDefinitionConstructionException;
import org.springframework.webflow.definition.registry.FlowDefinitionHolder;
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
import org.springframework.webflow.engine.builder.DefaultFlowHolder;
import org.springframework.webflow.engine.builder.FlowAssembler;
import org.springframework.webflow.engine.builder.FlowBuilder;
import org.springframework.webflow.engine.builder.FlowBuilderContext;
import org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder;
import org.springframework.webflow.engine.builder.support.FlowBuilderContextImpl;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
import org.springframework.webflow.engine.model.builder.DefaultFlowModelHolder;
import org.springframework.webflow.engine.model.builder.FlowModelBuilder;
import org.springframework.webflow.engine.model.builder.xml.XmlFlowModelBuilder;
import org.springframework.webflow.engine.model.registry.FlowModelHolder;

/**
* A factory for a flow definition registry. Is a Spring FactoryBean, for provision by the flow definition registry bean
* definition parser. Is package-private, as people should not be using this class directly, but rather through the
* higher-level webflow-config Spring 2.x configuration namespace.
*
* @author Keith Donald
* @author Jeremy Grelle
* @author Scott Andrews
*/
class FlowRegistryFactoryBean implements FactoryBean<FlowDefinitionRegistry>, BeanClassLoaderAware, InitializingBean,
    DisposableBean {

  private FlowLocation[] flowLocations;

  private String[] flowLocationPatterns;

  private FlowBuilderInfo[] flowBuilders;

  private FlowBuilderServices flowBuilderServices;

  private FlowDefinitionRegistry parent;

  private String basePath;

  private ClassLoader classLoader;

  /**
   * The definition registry produced by this factory bean.
   */
  private DefaultFlowRegistry flowRegistry;

  /**
   * A helper for creating abstract representation of externalized flow definition resources.
   */
  private FlowDefinitionResourceFactory flowResourceFactory;

  /**
   * Flow definitions defined in external files that should be registered in the registry produced by this factory
   * bean.
   */
  public void setFlowLocations(FlowLocation... flowLocations) {
    this.flowLocations = flowLocations;
  }

  /**
   * Resolvable path patterns to flows to register in the registry produced by this factory bean.
   */
  public void setFlowLocationPatterns(String... flowLocationPatterns) {
    this.flowLocationPatterns = flowLocationPatterns;
  }

  /**
   * Java {@link FlowBuilder flow builder} classes that should be registered in the registry produced by this factory
   * bean.
   */
  public void setFlowBuilders(FlowBuilderInfo... flowBuilders) {
    this.flowBuilders = flowBuilders;
  }

  /**
   * The holder for services needed to build flow definitions registered in this registry.
   */
  public void setFlowBuilderServices(FlowBuilderServices flowBuilderServices) {
    this.flowBuilderServices = flowBuilderServices;
  }

  /**
   * Base path used when determining the default flow id
   */
  public void setBasePath(String basePath) {
    this.basePath = basePath;
  }

  /**
   * The parent of the registry created by this factory bean.
   */
  public void setParent(FlowDefinitionRegistry parent) {
    this.parent = parent;
  }

  // implement BeanClassLoaderAware

  public void setBeanClassLoader(ClassLoader classLoader) {
    this.classLoader = classLoader;
  }

  public void afterPropertiesSet() throws Exception {
    flowResourceFactory = new FlowDefinitionResourceFactory(flowBuilderServices.getApplicationContext());
    if (basePath != null) {
      flowResourceFactory.setBasePath(basePath);
    }
    flowRegistry = new DefaultFlowRegistry();
    flowRegistry.setParent(parent);
    registerFlowLocations();
    registerFlowLocationPatterns();
    registerFlowBuilders();
  }

  public FlowDefinitionRegistry getObject() throws Exception {
    return flowRegistry;
  }

  public Class<?> getObjectType() {
    return FlowDefinitionRegistry.class;
  }

  public boolean isSingleton() {
    return true;
  }

  // implement DisposableBean

  public void destroy() throws Exception {
    flowRegistry.destroy();
  }

  private void registerFlowLocations() {
    if (flowLocations != null) {
      for (FlowLocation location : flowLocations) {
        flowRegistry.registerFlowDefinition(createFlowDefinitionHolder(createResource(location)));
      }
    }
  }

  private void registerFlowLocationPatterns() {
    if (flowLocationPatterns != null) {
      for (String pattern : flowLocationPatterns) {
        FlowDefinitionResource[] resources;
        AttributeMap<Object> attributes = getFlowAttributes(Collections.<FlowElementAttribute> emptySet());
        try {
          resources = flowResourceFactory.createResources(pattern, attributes);
        } catch (IOException e) {
          IllegalStateException ise = new IllegalStateException(
              "An I/O Exception occurred resolving the flow location pattern '" + pattern + "'");
          ise.initCause(e);
          throw ise;
        }
        for (FlowDefinitionResource resource : resources) {
          flowRegistry.registerFlowDefinition(createFlowDefinitionHolder(resource));
        }
      }
    }
  }

  private void registerFlowBuilders() {
    if (flowBuilders != null) {
      for (FlowBuilderInfo builderInfo : flowBuilders) {
        flowRegistry.registerFlowDefinition(buildFlowDefinition(builderInfo));
      }
    }
  }

  private FlowDefinitionHolder createFlowDefinitionHolder(FlowDefinitionResource flowResource) {
    FlowBuilder builder = createFlowBuilder(flowResource);
    FlowBuilderContext builderContext = new FlowBuilderContextImpl(flowResource.getId(),
        flowResource.getAttributes(), flowRegistry, flowBuilderServices);
    FlowAssembler assembler = new FlowAssembler(builder, builderContext);
    return new DefaultFlowHolder(assembler);
  }

  private FlowDefinitionResource createResource(FlowLocation location) {
    AttributeMap<Object> flowAttributes = getFlowAttributes(location.getAttributes());
    return flowResourceFactory.createResource(location.getPath(), flowAttributes, location.getId());
  }

  private AttributeMap<Object> getFlowAttributes(Set<FlowElementAttribute> attributes) {
    MutableAttributeMap<Object> flowAttributes = null;
    if (flowBuilderServices.getDevelopment()) {
      flowAttributes = new LocalAttributeMap<Object>(1 + attributes.size(), 1);
      flowAttributes.put("development", true);
    }
    if (!attributes.isEmpty()) {
      if (flowAttributes == null) {
        flowAttributes = new LocalAttributeMap<Object>(attributes.size(), 1);
      }
      for (FlowElementAttribute attribute : attributes) {
        flowAttributes.put(attribute.getName(), getConvertedValue(attribute));
      }
    }
    return flowAttributes;
  }

  private FlowBuilder createFlowBuilder(FlowDefinitionResource resource) {
    return new FlowModelFlowBuilder(createFlowModelHolder(resource));
  }

  private FlowModelHolder createFlowModelHolder(FlowDefinitionResource resource) {
    FlowModelHolder modelHolder = new DefaultFlowModelHolder(createFlowModelBuilder(resource));
    // register the flow model holder with the backing flow model registry - this is needed to support flow model
    // merging during the flow build process
    flowRegistry.getFlowModelRegistry().registerFlowModel(resource.getId(), modelHolder);
    return modelHolder;
  }

  private FlowModelBuilder createFlowModelBuilder(FlowDefinitionResource resource) {
    if (isXml(resource.getPath())) {
      return new XmlFlowModelBuilder(resource.getPath(), flowRegistry.getFlowModelRegistry());
    } else {
      throw new IllegalArgumentException(resource
          + " is not a supported resource type; supported types are [.xml]");
    }
  }

  private boolean isXml(Resource flowResource) {
    return flowResource.getFilename().endsWith(".xml");
  }

  private Object getConvertedValue(FlowElementAttribute attribute) {
    if (attribute.needsTypeConversion()) {
      Class<?> targetType = fromStringToClass(attribute.getType());
      ConversionExecutor converter = flowBuilderServices.getConversionService().getConversionExecutor(
          String.class, targetType);
      return converter.execute(attribute.getValue());
    } else {
      return attribute.getValue();
    }
  }

  private Class<?> fromStringToClass(String name) {
    Class<?> clazz = flowBuilderServices.getConversionService().getClassForAlias(name);
    if (clazz != null) {
      return clazz;
    } else {
      return loadClass(name);
    }
  }

  private Class<?> loadClass(String name) {
    try {
      return ClassUtils.forName(name, classLoader);
    } catch (ClassNotFoundException e) {
      throw new IllegalArgumentException("Unable to load class '" + name + "'");
    }
  }

  private FlowDefinition buildFlowDefinition(FlowBuilderInfo builderInfo) {
    try {
      Class<?> flowBuilderClass = loadClass(builderInfo.getClassName());
      FlowBuilder builder = (FlowBuilder) flowBuilderClass.newInstance();
      AttributeMap<Object> flowAttributes = getFlowAttributes(builderInfo.getAttributes());
      FlowBuilderContext builderContext = new FlowBuilderContextImpl(builderInfo.getId(), flowAttributes,
          flowRegistry, flowBuilderServices);
      FlowAssembler assembler = new FlowAssembler(builder, builderContext);
      return assembler.assembleFlow();
    } catch (IllegalArgumentException e) {
      throw new FlowDefinitionConstructionException(builderInfo.getId(), e);
    } catch (InstantiationException e) {
      throw new FlowDefinitionConstructionException(builderInfo.getId(), e);
    } catch (IllegalAccessException e) {
      throw new FlowDefinitionConstructionException(builderInfo.getId(), e);
    }
  }

}
TOP

Related Classes of org.springframework.webflow.config.FlowRegistryFactoryBean

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.