View Javadoc

1   /*
2    * Copyright 2006 Outsource Cafe, Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the 'License')
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an 'AS IS' BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.javagen.agile.core.visitor;
17  
18  import java.util.HashMap;
19  import java.util.Map;
20  
21  import org.javagen.agile.core.model.Model;
22  
23  /***
24   * Defines a generic, extensible visitor pattern based on registering a 
25   * <code>Visit</code> instance for each <code>Model</code> type.
26   * <p>
27   * The biggest problem with the traditional visitor pattern is that it binds you to a 
28   * fixed set of node types witch is not good in an open-ended framework
29   * like JavaGen-Agile.  This visitor pattern avoids that by allowing any number
30   * of <code>Visit</code> methods to be registered by <code>Model</code> type.
31   * <p>
32   * Arbitrary model hierarchies can be combined as this example illustrates:
33   * <pre>
34   * Visitor visitor = new TypeLookupVisitor( new OOLookupVisitor(), new DBLookupVisitor() );
35   * visitor.visit( combinedModelTree );
36   * </pre> 
37   *
38   * @author Richard Easterling
39   */
40  public class TypeLookupVisitor extends DefaultVisitor {
41  
42      @SuppressWarnings("unchecked")
43      protected Map<Class, Visit> visitInstances = new HashMap<Class, Visit>();
44      
45      protected Visit defualtVisit;
46      
47      public TypeLookupVisitor() {}
48      
49      public TypeLookupVisitor(TypeLookupVisitor[] lookupVisitorDelegates) {
50          for(TypeLookupVisitor lookupVisitor : lookupVisitorDelegates)
51              this.addVisitInstances(lookupVisitor.getVisitInstances());
52      }
53      
54      ////////////////////////////////////////////////////////////////////////////
55      // Visit interface:
56      ////////////////////////////////////////////////////////////////////////////
57      
58      /***
59       * Lookup Visit instance for this model type and invoke <code>visit</code> method.
60       * If no <code>Visit</code> instance is registered for a given type, the <code>defaultVisit</code>
61       * method will be invoked if one has been specified.
62       * <p>
63       * Note: this method is only called if there is either no itinerary or the itinerary includes 
64       * this <code>modelType</code>. 
65       */
66      public void visit(Model model) {
67          Visit visit = get(model.getClass());
68          if (visit!=null) {
69              visit.visit(model);
70          } else {
71              if (defualtVisit!=null)
72                  defualtVisit.visit(model);
73          }
74      }
75  
76      ////////////////////////////////////////////////////////////////////////////
77      // Visit lookup handling:
78      ////////////////////////////////////////////////////////////////////////////
79      
80      @SuppressWarnings("unchecked")
81      public void addVisitInstances(Map<Class, Visit> visitInstances) {
82          for(Map.Entry<Class,Visit> entry : visitInstances.entrySet())
83              put(entry.getKey(), entry.getValue());
84      }
85      
86      @SuppressWarnings("unchecked")
87      public void put(Class clazz, Visit visit) {
88          if (clazz.equals(Model.class)) {
89              defualtVisit = visit;
90          } else {
91              visitInstances.put(clazz, visit);
92          }
93      }
94      
95      @SuppressWarnings("unchecked")
96      public Visit get(Class clazz) {
97          return this.visitInstances.get(clazz);
98      }
99  
100     @SuppressWarnings("unchecked")
101     public Map<Class, Visit> getVisitInstances() {
102         return visitInstances;
103     }
104 
105     @SuppressWarnings("unchecked")
106     public void setVisitInstances(Map<Class, Visit> visitInstances) {
107         this.visitInstances = visitInstances;
108     }
109     
110     public Visit getDefualtVisit() {
111         return defualtVisit;
112     }
113 
114     public void setDefualtVisit(Visit defualtVisit) {
115         this.defualtVisit = defualtVisit;
116     }
117 }