View Javadoc

1   package org.apache.helix.participant.statemachine;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.lang.reflect.Method;
23  import java.util.Arrays;
24  
25  import org.apache.helix.NotificationContext;
26  import org.apache.helix.model.Message;
27  
28  
29  /**
30   * Finds the method in stateModel to generate
31   * 
32   * 
33   */
34  public class StateModelParser
35  {
36  
37  	public Method getMethodForTransition(Class<? extends StateModel> clazz,
38  	    String fromState, String toState, Class<?>[] paramTypes)
39  	{
40  		Method method = getMethodForTransitionUsingAnnotation(clazz, fromState,
41  		    toState, paramTypes);
42  		if (method == null)
43  		{
44  			method = getMethodForTransitionByConvention(clazz, fromState, toState,
45  			    paramTypes);
46  		}
47  		return method;
48  	}
49  
50  	/**
51  	 * This class uses the method naming convention "onBecome" + toState + "From"
52  	 * + fromState;
53  	 * 
54  	 * @param clazz
55  	 * @param fromState
56  	 * @param toState
57  	 * @param paramTypes
58  	 * @return Method if found else null
59  	 */
60  	public Method getMethodForTransitionByConvention(
61  	    Class<? extends StateModel> clazz, String fromState, String toState,
62  	    Class<?>[] paramTypes)
63  	{
64  		Method methodToInvoke = null;
65  		String methodName = "onBecome" + toState + "From" + fromState;
66  		if (fromState.equals("*"))
67  		{
68  			methodName = "onBecome" + toState;
69  		}
70  
71  		Method[] methods = clazz.getMethods();
72  		for (Method method : methods)
73  		{
74  			if (method.getName().equalsIgnoreCase(methodName))
75  			{
76  				Class<?>[] parameterTypes = method.getParameterTypes();
77  				if (parameterTypes.length == 2
78  				    && parameterTypes[0].equals(Message.class)
79  				    && parameterTypes[1].equals(NotificationContext.class))
80  				{
81  					methodToInvoke = method;
82  					break;
83  				}
84  			}
85  		}
86  		return methodToInvoke;
87  
88  	}
89  
90  	/**
91  	 * This method uses annotations on the StateModel class. Use StateModelInfo
92  	 * annotation to specify valid states and initial value use Transition to
93  	 * specify "to" and "from" state
94  	 * 
95  	 * @param clazz
96  	 *          , class which extends StateModel
97  	 * @param fromState
98  	 * @param toState
99  	 * @param paramTypes
100 	 * @return
101 	 */
102 	public Method getMethodForTransitionUsingAnnotation(
103 	    Class<? extends StateModel> clazz, String fromState, String toState,
104 	    Class<?>[] paramTypes)
105 	{
106 		StateModelInfo stateModelInfo = clazz.getAnnotation(StateModelInfo.class);
107 		Method methodToInvoke = null;
108 		if (stateModelInfo != null)
109 		{
110 			Method[] methods = clazz.getMethods();
111 			if (methods != null)
112 			{
113 				for (Method method : methods)
114 				{
115 					Transition annotation = method.getAnnotation(Transition.class);
116 					if (annotation != null)
117 					{
118 						boolean matchesFrom = "*".equals(annotation.from()) || annotation.from().equalsIgnoreCase(fromState);
119 						boolean matchesTo = "*".equals(annotation.to()) || annotation.to().equalsIgnoreCase(toState);
120 						boolean matchesParamTypes = Arrays.equals(paramTypes,
121 						    method.getParameterTypes());
122 						if (matchesFrom && matchesTo && matchesParamTypes)
123 						{
124 							methodToInvoke = method;
125 							break;
126 						}
127 					}
128 				}
129 			}
130 		}
131 
132 		return methodToInvoke;
133 	}
134 
135 	/**
136 	 * Get the initial state for the state model
137 	 * 
138 	 * @param clazz
139 	 * @return
140 	 */
141 	public String getInitialState(Class<? extends StateModel> clazz)
142 	{
143 		StateModelInfo stateModelInfo = clazz.getAnnotation(StateModelInfo.class);
144 		if (stateModelInfo != null)
145 		{
146 			return stateModelInfo.initialState();
147 		}else{
148 			return StateModel.DEFAULT_INITIAL_STATE;
149 		}
150 	}
151 
152 }