View Javadoc

1   /*
2    * $Id: TransformerWeighting.java 19191 2010-08-25 21:05:23Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  package org.mule.transformer;
11  
12  import org.mule.api.transformer.DataType;
13  import org.mule.api.transformer.DiscoverableTransformer;
14  import org.mule.api.transformer.Transformer;
15  
16  import java.util.List;
17  
18  /**
19   * Given a {@link org.mule.api.transformer.Transformer} instance, an input class and output class
20   * this object will create a weighting for a transformer. This weighthing can be used compare one transformer with
21   * another, which can be useful for choosing a transformer to use given the input class and required output class.
22   */
23  public class TransformerWeighting implements Comparable
24  {
25      private Transformer transformer;
26      private int inputWeighting;
27      private int outputWeighting;
28      private Class inputClass;
29      private Class outputClass;
30  
31      public TransformerWeighting(Class inputClass, Class outputClass, Transformer transformer)
32      {
33          this.inputClass = inputClass;
34          this.outputClass = outputClass;
35          this.transformer = transformer;
36          init();
37      }
38  
39      private void init()
40      {
41          inputWeighting = Integer.MAX_VALUE;
42          List<DataType<?>> sourceTypes = transformer.getSourceDataTypes();
43  
44          for (DataType type : sourceTypes)
45          {
46              int weighting = getWeighting(-1, inputClass, type.getType());
47              if (weighting < inputWeighting && weighting != -1)
48              {
49                  inputWeighting = weighting;
50              }
51          }
52  
53          outputWeighting = getWeighting(-1, outputClass, transformer.getReturnClass());
54  
55          inputWeighting = (inputWeighting == Integer.MAX_VALUE ? -1 : inputWeighting);
56          outputWeighting = (outputWeighting == Integer.MAX_VALUE ? -1 : outputWeighting);
57  
58      }
59  
60      /**
61       * THis is a very basic algorithm for creating a match rating for two classes.  An offset weighting
62       * can also be passed in. Where w is weighting,
63       * if the classes match exactly, w+1 is returned,
64       * if the classes are assignable and there is a direct equality to an interface on the class, w+2  is returned,
65       * if the classes are assignable but no direct interface match, w+3 is returned
66       * If the dest type is Object.class then w+4is returned. This is because matching on object will yeild a lot of options
67       * putting those that use the Object.class generic type should get pushed down the list
68       * If there a super class, that will get matched using the above criteria
69       * If there is no match -1 is returned
70       *
71       * @param weighting an offset weighting, by defualt -1 should be used
72       * @param src the src class being matched
73       * @param dest the destination class to match to
74       * @return a weighting where 0 would be an exact match, -1 would be no match and a positive integer that defines how close the match is
75       */
76      protected int getWeighting(int weighting, Class src, Class dest)
77      {
78          int x = weighting + 1;
79          //If we are getting a match for object.class, we need to put it at the bottom of
80          //the matching list
81          if(dest.equals(Object.class))
82          {
83              return x + 3;
84          }
85  
86          if (dest.equals(src))
87          {
88              return x;
89          }
90          else if (!dest.isAssignableFrom(src))
91          {
92              return -1;
93          }
94          else if (src.getInterfaces().length > 0)
95          {
96              for (int i = 0; i < src.getInterfaces().length; i++)
97              {
98                  Class aClass = src.getInterfaces()[i];
99                  if (dest.equals(aClass))
100                 {
101                     return x + 1;
102                 }
103             }
104             return x + 2;
105         }
106         else if (src.getSuperclass() != null)
107         {
108             return getWeighting(x, src.getSuperclass(), dest);
109 
110         }
111         return -1;
112     }
113 
114     public Class getInputClass()
115     {
116         return inputClass;
117     }
118 
119     public int getInputWeighting()
120     {
121         return inputWeighting;
122     }
123 
124     public Class getOutputClass()
125     {
126         return outputClass;
127     }
128 
129     public int getOutputWeighting()
130     {
131         return outputWeighting;
132     }
133 
134     public Transformer getTransformer()
135     {
136         return transformer;
137     }
138 
139     public boolean isExactMatch()
140     {
141         return inputWeighting == 0 && outputWeighting == 0;
142     }
143 
144     public boolean isNotMatch()
145     {
146         return inputWeighting == -1 || outputWeighting == -1;
147     }
148 
149     public int compareTo(Object o)
150     {
151         TransformerWeighting weighting = (TransformerWeighting) o;
152         if (weighting.getInputWeighting() == getInputWeighting() &&
153                 weighting.getOutputWeighting() == getOutputWeighting())
154         {
155             //We only check the weighting if we have an exact match
156             //These transformers should always implement DiscoverableTransformer, but jic we check here
157             if (weighting.getTransformer() instanceof DiscoverableTransformer
158                     && this.getTransformer() instanceof DiscoverableTransformer)
159             {
160                 int x = ((DiscoverableTransformer) weighting.getTransformer()).getPriorityWeighting();
161                 int y = ((DiscoverableTransformer) this.getTransformer()).getPriorityWeighting();
162                 if (x > y)
163                 {
164                     return -1;
165                 }
166                 if (x < y)
167                 {
168                     return 1;
169                 }
170                 return 0;
171             }
172             else
173             {
174                 return 0;
175             }
176         }
177         else
178         {
179             if (isNotMatch())
180             {
181                 return -1;
182             }
183             else if (weighting.isNotMatch() && !isNotMatch())
184             {
185                 return 1;
186             }
187             else if (weighting.isExactMatch() && !isExactMatch())
188             {
189                 return -1;
190             }
191             else if (weighting.getInputWeighting() < getInputWeighting() &&
192                     weighting.getOutputWeighting() < getOutputWeighting())
193             {
194                 return -1;
195             }
196             //If the outputWeighting is closer to 0 its a better match
197             else if (weighting.getInputWeighting() == getInputWeighting() &&
198                     weighting.getOutputWeighting() < getOutputWeighting())
199             {
200                 return -1;
201             }
202 
203             else if (weighting.getInputWeighting() < getInputWeighting() &&
204                     weighting.getOutputWeighting() == getOutputWeighting())
205             {
206                 return -1;
207             }
208             return 1;
209         }
210     }
211 
212     public boolean equals(Object o)
213     {
214         if (this == o)
215         {
216             return true;
217         }
218         if (o == null || getClass() != o.getClass())
219         {
220             return false;
221         }
222 
223         TransformerWeighting that = (TransformerWeighting) o;
224 
225         if (inputClass != null ? !inputClass.equals(that.inputClass) : that.inputClass != null)
226         {
227             return false;
228         }
229         if (outputClass != null ? !outputClass.equals(that.outputClass) : that.outputClass != null)
230         {
231             return false;
232         }
233 
234         return true;
235     }
236 
237     public int hashCode()
238     {
239         int result;
240         result = (transformer != null ? transformer.hashCode() : 0);
241         result = 31 * result + inputWeighting;
242         result = 31 * result + outputWeighting;
243         result = 31 * result + (inputClass != null ? inputClass.hashCode() : 0);
244         result = 31 * result + (outputClass != null ? outputClass.hashCode() : 0);
245         return result;
246     }
247 
248 
249     public String toString()
250     {
251         final StringBuffer sb = new StringBuffer();
252         sb.append("TransformerWeighting");
253         sb.append("{inputClass=").append(inputClass);
254         sb.append(", inputWeighting=").append(inputWeighting);
255         sb.append(", outputClass=").append(outputClass);
256         sb.append(", outputWeighting=").append(outputWeighting);
257         sb.append(", transformer=").append(transformer.getName());
258         sb.append('}');
259         return sb.toString();
260     }
261 }