content: /*
   * RegistryMatcher.java May 2011
   *
   * Copyright (C) 2011, Niall Gallagher <niallg@users.sf.net>
   *
   * 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 com.aliyun.odps.simpleframework.xml.transform;
  
  import com.aliyun.odps.simpleframework.xml.core.Persister;
  import com.aliyun.odps.simpleframework.xml.util.Cache;
  import com.aliyun.odps.simpleframework.xml.util.ConcurrentCache;
  
  /**
   * The <code>RegistryMatcher</code> provides a simple matcher backed
   * by a registry. Registration can be done to match a type to a
   * <code>Transform</code> class or instance. If a transform class is
   * registered an instance of it is created when requested using the
   * default no argument constructor of the type, it is then cached so 
   * it can be reused on future requests.
   * 
   * @author Niall Gallagher
   * 
   * @see Persister
   */
  public class RegistryMatcher implements Matcher {
     
     /**
      * This is used to fetch transform instances by type.
      */
     private final Cache<Transform> transforms;
     
     /**
      * This is used to determine the transform  for a type.
      */
     private final Cache<Class> types;
     
     /**
      * Constructor for the <code>RegistryMatcher</code>. This is used
      * to create a matcher instance that can resolve a transform by
      * type and can also instantiate new transforms if required. It 
      * is essentially a convenience implementation.
      */
     public RegistryMatcher() {
        this.transforms = new ConcurrentCache<Transform>();
        this.types = new ConcurrentCache<Class>();
     }
     
     /**
      * This is used to bind a <code>Transform</code> type. The first 
      * time a transform is requested for the specified type a new 
      * instance of this <code>Transform</code> will be instantiated.
      * 
      * @param type this is the type to resolve the transform for
      * @param transform this is the transform type to instantiate
      */
     public void bind(Class type, Class transform) {
        types.cache(type, transform);
     }
     
     /**
      * This is used to bind a <code>Transform</code> instance to the
      * specified type. Each time a transform is requested for this
      * type the provided instance will be returned.
      * 
      * @param type this is the type to resolve the transform for
      * @param transform this transform instance to be used
      */
     public void bind(Class type, Transform transform) {
        transforms.cache(type, transform);
     }
     
     /**
      * This is used to match a <code>Transform</code> using the type
      * specified. If no transform can be acquired then this returns
      * a null value indicating that no transform could be found.
      * 
      * @param type this is the type to acquire the transform for
      * 
      * @return returns a transform for processing the type given
      */ 
     public Transform match(Class type) throws Exception {
        Transform transform = transforms.fetch(type);
        
        if(transform == null) {
           return create(type);
        }
        return transform;
     }
     
     /**
      * This is used to create a <code>Transform</code> using the type
      * specified. If no transform can be acquired then this returns
      * a null value indicating that no transform could be found.
      * 
      * @param type this is the type to acquire the transform for
      * 
      * @return returns a transform for processing the type given
      */ 
     private Transform create(Class type) throws Exception {
        Class factory = types.fetch(type);
        
        if(factory != null) {
           return create(type, factory);
        }
        return null;
     }
     
     /**
      * This is used to create a <code>Transform</code> using the type
      * specified. If the transform can not be instantiated then this
      * will throw an exception. If it can then it is cached.
      * 
      * @param type this is the type to acquire the transform for
      * @param factory the class for instantiating the transform
      * 
      * @return returns a transform for processing the type given
      */ 
     private Transform create(Class type, Class factory) throws Exception {
        Object value = factory.newInstance();
        Transform transform = (Transform)value;
           
        if(transform != null) {
           transforms.cache(type, transform);
        }
        return transform;
     }
  }
  