001/*
002 * RegistryMatcher.java May 2011
003 *
004 * Copyright (C) 2011, Niall Gallagher <niallg@users.sf.net>
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
015 * implied. See the License for the specific language governing 
016 * permissions and limitations under the License.
017 */
018
019package org.simpleframework.xml.transform;
020
021import org.simpleframework.xml.util.Cache;
022import org.simpleframework.xml.util.ConcurrentCache;
023
024/**
025 * The <code>RegistryMatcher</code> provides a simple matcher backed
026 * by a registry. Registration can be done to match a type to a
027 * <code>Transform</code> class or instance. If a transform class is
028 * registered an instance of it is created when requested using the
029 * default no argument constructor of the type, it is then cached so 
030 * it can be reused on future requests.
031 * 
032 * @author Niall Gallagher
033 * 
034 * @see org.simpleframework.xml.core.Persister
035 */
036public class RegistryMatcher implements Matcher {
037   
038   /**
039    * This is used to fetch transform instances by type.
040    */
041   private final Cache<Transform> transforms;
042   
043   /**
044    * This is used to determine the transform  for a type.
045    */
046   private final Cache<Class> types;
047   
048   /**
049    * Constructor for the <code>RegistryMatcher</code>. This is used
050    * to create a matcher instance that can resolve a transform by
051    * type and can also instantiate new transforms if required. It 
052    * is essentially a convenience implementation.
053    */
054   public RegistryMatcher() {
055      this.transforms = new ConcurrentCache<Transform>();
056      this.types = new ConcurrentCache<Class>();
057   }
058   
059   /**
060    * This is used to bind a <code>Transform</code> type. The first 
061    * time a transform is requested for the specified type a new 
062    * instance of this <code>Transform</code> will be instantiated.
063    * 
064    * @param type this is the type to resolve the transform for
065    * @param transform this is the transform type to instantiate
066    */
067   public void bind(Class type, Class transform) {
068      types.cache(type, transform);
069   }
070   
071   /**
072    * This is used to bind a <code>Transform</code> instance to the
073    * specified type. Each time a transform is requested for this
074    * type the provided instance will be returned.
075    * 
076    * @param type this is the type to resolve the transform for
077    * @param transform this transform instance to be used
078    */
079   public void bind(Class type, Transform transform) {
080      transforms.cache(type, transform);
081   }
082   
083   /**
084    * This is used to match a <code>Transform</code> using the type
085    * specified. If no transform can be acquired then this returns
086    * a null value indicating that no transform could be found.
087    * 
088    * @param type this is the type to acquire the transform for
089    * 
090    * @return returns a transform for processing the type given
091    */ 
092   public Transform match(Class type) throws Exception {
093      Transform transform = transforms.fetch(type);
094      
095      if(transform == null) {
096         return create(type);
097      }
098      return transform;
099   }
100   
101   /**
102    * This is used to create a <code>Transform</code> using the type
103    * specified. If no transform can be acquired then this returns
104    * a null value indicating that no transform could be found.
105    * 
106    * @param type this is the type to acquire the transform for
107    * 
108    * @return returns a transform for processing the type given
109    */ 
110   private Transform create(Class type) throws Exception {
111      Class factory = types.fetch(type);
112      
113      if(factory != null) {
114         return create(type, factory);
115      }
116      return null;
117   }
118   
119   /**
120    * This is used to create a <code>Transform</code> using the type
121    * specified. If the transform can not be instantiated then this
122    * will throw an exception. If it can then it is cached.
123    * 
124    * @param type this is the type to acquire the transform for
125    * @param factory the class for instantiating the transform
126    * 
127    * @return returns a transform for processing the type given
128    */ 
129   private Transform create(Class type, Class factory) throws Exception {
130      Object value = factory.newInstance();
131      Transform transform = (Transform)value;
132         
133      if(transform != null) {
134         transforms.cache(type, transform);
135      }
136      return transform;
137   }
138}