1 /***
2 *
3 * Copyright 2005 LogicBlaze, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 **/
18 package org.logicblaze.lingo;
19
20 import org.aopalliance.intercept.MethodInvocation;
21
22 import java.lang.reflect.Method;
23 import java.rmi.Remote;
24 import java.util.EventListener;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.Set;
28
29 /***
30 * A simple metadata strategy which uses POJO naming conventions.
31 *
32 * By default all method invocations are synchronous to avoid surprising users
33 * of Spring Remoting. However if you set the
34 * {@link #setOneWayForVoidMethods(boolean)} value to true then all void methods
35 * which do not throw checked exceptions become asynchronous one way methods.
36 *
37 * <p/> Also any object which implements the {@link Remote} interface or the
38 * {@link EventListener} are assumed to be remote and so a remote proxy is used
39 * to allow remote notifications and asynchronous messaging.
40 *
41 * @version $Revision: 1.8 $
42 */
43 public class SimpleMetadataStrategy implements MetadataStrategy {
44 private static final long serialVersionUID = 3314789109318386510L;
45
46 private boolean oneWayForVoidMethods;
47 private Set remoteTypes;
48 private ResultJoinStrategy resultJoinStrategy = new DefaultResultJoinStrategy();
49
50 public SimpleMetadataStrategy() {
51 }
52
53 public SimpleMetadataStrategy(boolean oneWayForVoidMethods) {
54 this.oneWayForVoidMethods = oneWayForVoidMethods;
55 }
56
57 public MethodMetadata getMethodMetadata(Method method) {
58 boolean oneway = isOneWayMethod(method);
59 boolean[] remoteParams = null;
60 Class[] parameterTypes = method.getParameterTypes();
61 int size = parameterTypes.length;
62 if (size > 0) {
63 remoteParams = new boolean[size];
64 for (int i = 0; i < size; i++) {
65 remoteParams[i] = isRemoteParameter(method, parameterTypes[i], i);
66 }
67 }
68 return new MethodMetadata(oneway, remoteParams, isStateful(method), isEndSession(method));
69 }
70
71 public boolean isOneWayForVoidMethods() {
72 return oneWayForVoidMethods;
73 }
74
75 public void setOneWayForVoidMethods(boolean oneWayForVoidMethods) {
76 this.oneWayForVoidMethods = oneWayForVoidMethods;
77 }
78
79 public ResultJoinStrategy getResultJoinStrategy(MethodInvocation methodInvocation, MethodMetadata metadata) {
80 return getResultJoinStrategy();
81 }
82
83 public ResultJoinStrategy getResultJoinStrategy() {
84 return resultJoinStrategy;
85 }
86
87 public void setResultJoinStrategy(ResultJoinStrategy joinStrategy) {
88 this.resultJoinStrategy = joinStrategy;
89 }
90
91 public Set getRemoteTypes() {
92 if (remoteTypes == null) {
93 remoteTypes = new HashSet();
94 populateDefaultRemoteTypes(remoteTypes);
95 }
96 return remoteTypes;
97 }
98
99 public void setRemoteTypes(Set remoteTypes) {
100 this.remoteTypes = remoteTypes;
101 }
102
103 public boolean isRemoteParameter(Method method, Class parameterType, int index) {
104 for (Iterator iter = getRemoteTypes().iterator(); iter.hasNext();) {
105 Class type = (Class) iter.next();
106 if (type.isAssignableFrom(parameterType)) {
107 return true;
108 }
109 }
110 return false;
111 }
112
113
114
115 protected boolean isOneWayMethod(Method method) {
116 boolean oneway = false;
117 if (oneWayForVoidMethods) {
118 oneway = method.getReturnType().equals(void.class) && method.getExceptionTypes().length == 0;
119 }
120 return oneway;
121 }
122
123 /***
124 * Returns true if this method completes a callback object
125 */
126 protected boolean isEndSession(Method method) {
127 return false;
128 }
129
130 /***
131 * Returns whether or not this object is stateful such that sticky load
132 * balancing should be used
133 */
134 protected boolean isStateful(Method method) {
135 return false;
136 }
137
138 protected void populateDefaultRemoteTypes(Set remoteTypes) {
139 remoteTypes.add(Remote.class);
140 remoteTypes.add(EventListener.class);
141 }
142
143 }