001
014
015 package com.liferay.portal.kernel.jsonwebservice;
016
017 import com.liferay.portal.kernel.exception.PortalException;
018 import com.liferay.portal.kernel.exception.SystemException;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021 import com.liferay.portal.kernel.util.CharPool;
022 import com.liferay.portal.kernel.util.ContextPathUtil;
023 import com.liferay.portal.kernel.util.PropsKeys;
024 import com.liferay.portal.kernel.util.PropsUtil;
025 import com.liferay.portal.kernel.util.SetUtil;
026 import com.liferay.portal.kernel.util.StringBundler;
027 import com.liferay.portal.kernel.util.StringUtil;
028
029 import java.io.IOException;
030 import java.io.InputStream;
031
032 import java.lang.reflect.Method;
033 import java.lang.reflect.Modifier;
034
035 import java.util.Arrays;
036 import java.util.HashMap;
037 import java.util.Map;
038 import java.util.Set;
039
040 import javax.servlet.ServletContext;
041
042
046 public abstract class BaseJSONWebServiceConfigurator
047 implements JSONWebServiceConfigurator {
048
049 public void clean() {
050 int count =
051 JSONWebServiceActionsManagerUtil.unregisterJSONWebServiceActions(
052 _contextPath);
053
054 _registeredActionsCount -= count;
055
056 if (_log.isDebugEnabled()) {
057 if (count != 0) {
058 _log.debug(
059 "Removed " + count +
060 " existing JSON Web Service actions that belonged to " +
061 _contextPath);
062 }
063 }
064 }
065
066 public abstract void configure() throws PortalException, SystemException;
067
068 public ClassLoader getClassLoader() {
069 return _classLoader;
070 }
071
072 public String getContextPath() {
073 return _contextPath;
074 }
075
076 public int getRegisteredActionsCount() {
077 return _registeredActionsCount;
078 }
079
080 public ServletContext getServletContext() {
081 return _servletContext;
082 }
083
084 public void init(ServletContext servletContext, ClassLoader classLoader) {
085 _servletContext = servletContext;
086 _classLoader = classLoader;
087
088 _contextPath = ContextPathUtil.getContextPath(servletContext);
089 }
090
091 public void registerClass(String className, InputStream inputStream)
092 throws Exception {
093
094 if (!className.endsWith("Service") &&
095 !className.endsWith("ServiceImpl")) {
096
097 return;
098 }
099
100 if (inputStream.markSupported()) {
101 inputStream.mark(Integer.MAX_VALUE);
102 }
103
104 if (!isTypeSignatureInUse(inputStream)) {
105 return;
106 }
107
108 if (inputStream.markSupported()) {
109 inputStream.reset();
110
111 try {
112 JSONWebServiceClassVisitor jsonWebServiceClassVisitor =
113 JSONWebServiceClassVisitorFactoryUtil.create(inputStream);
114
115 jsonWebServiceClassVisitor.accept();
116
117 if (!className.equals(
118 jsonWebServiceClassVisitor.getClassName())) {
119
120 return;
121 }
122 }
123 catch (Exception e) {
124 _log.error(e, e);
125
126 return;
127 }
128 }
129
130 onJSONWebServiceClass(className);
131 }
132
133 protected byte[] getTypeSignatureBytes(Class<?> clazz) {
134 return ('L' + clazz.getName().replace('.', '/') + ';').getBytes();
135 }
136
137 protected boolean hasAnnotatedServiceImpl(String className) {
138 StringBundler sb = new StringBundler(4);
139
140 int pos = className.lastIndexOf(CharPool.PERIOD);
141
142 sb.append(className.substring(0, pos));
143 sb.append(".impl");
144 sb.append(className.substring(pos));
145 sb.append("Impl");
146
147 Class<?> implClass = null;
148
149 try {
150 implClass = _classLoader.loadClass(sb.toString());
151 }
152 catch (ClassNotFoundException cnfe) {
153 return false;
154 }
155
156 if (implClass.getAnnotation(JSONWebService.class) != null) {
157 return true;
158 }
159 else {
160 return false;
161 }
162 }
163
164 protected boolean isJSONWebServiceClass(Class<?> clazz) {
165 if (!clazz.isAnonymousClass() && !clazz.isArray() && !clazz.isEnum() &&
166 !clazz.isLocalClass() && !clazz.isPrimitive() &&
167 !(clazz.isMemberClass() ^
168 Modifier.isStatic(clazz.getModifiers()))) {
169
170 return true;
171 }
172
173 return false;
174 }
175
176 protected boolean isTypeSignatureInUse(InputStream inputStream) {
177 try {
178
179
180
181 byte[] buffer = new byte[_jsonWebServiceAnnotationBytes.length];
182
183
184
185 int value = inputStream.read(buffer);
186
187
188
189 if (value < _jsonWebServiceAnnotationBytes.length) {
190 return false;
191 }
192
193
194
195 if (Arrays.equals(buffer, _jsonWebServiceAnnotationBytes)) {
196 return true;
197 }
198
199
200
201 while ((value = inputStream.read()) != -1) {
202
203
204
205 if (value == -1) {
206 return false;
207 }
208
209
210
211 System.arraycopy(buffer, 1, buffer, 0, buffer.length - 1);
212
213
214
215 buffer[buffer.length - 1] = (byte)value;
216
217
218
219 if (Arrays.equals(buffer, _jsonWebServiceAnnotationBytes)) {
220 return true;
221 }
222 }
223 }
224 catch (IOException ioe) {
225 throw new IllegalStateException(
226 "Unable to read bytes from input stream", ioe);
227 }
228
229 return false;
230 }
231
232 protected Class<?> loadUtilClass(Class<?> implementationClass)
233 throws ClassNotFoundException {
234
235 Class<?> utilClass = _utilClasses.get(implementationClass);
236
237 if (utilClass != null) {
238 return utilClass;
239 }
240
241 String utilClassName = implementationClass.getName();
242
243 if (utilClassName.endsWith("Impl")) {
244 utilClassName = utilClassName.substring(
245 0, utilClassName.length() - 4);
246
247 }
248
249 utilClassName += "Util";
250
251 utilClassName = StringUtil.replace(utilClassName, ".impl.", ".");
252
253 utilClass = _classLoader.loadClass(utilClassName);
254
255 _utilClasses.put(implementationClass, utilClass);
256
257 return utilClass;
258 }
259
260 protected void onJSONWebServiceClass(String className) throws Exception {
261 Class<?> actionClass = _classLoader.loadClass(className);
262
263 if (!isJSONWebServiceClass(actionClass)) {
264 return;
265 }
266
267 if (actionClass.isInterface() && hasAnnotatedServiceImpl(className)) {
268 return;
269 }
270
271 JSONWebService classJSONWebService = actionClass.getAnnotation(
272 JSONWebService.class);
273
274 JSONWebServiceMode classJSONWebServiceMode = JSONWebServiceMode.MANUAL;
275
276 if (classJSONWebService != null) {
277 classJSONWebServiceMode = classJSONWebService.mode();
278 }
279
280 Method[] methods = actionClass.getMethods();
281
282 for (Method method : methods) {
283 Class<?> methodDeclaringClass = method.getDeclaringClass();
284
285 if (!methodDeclaringClass.equals(actionClass)) {
286 continue;
287 }
288
289 if ((_excludedMethodNames != null) &&
290 _excludedMethodNames.contains(method.getName())) {
291
292 continue;
293 }
294
295 boolean registerMethod = false;
296
297 JSONWebService methodJSONWebService = method.getAnnotation(
298 JSONWebService.class);
299
300 if (classJSONWebServiceMode.equals(JSONWebServiceMode.AUTO)) {
301 registerMethod = true;
302
303 if (methodJSONWebService != null) {
304 JSONWebServiceMode methodJSONWebServiceMode =
305 methodJSONWebService.mode();
306
307 if (methodJSONWebServiceMode.equals(
308 JSONWebServiceMode.IGNORE)) {
309
310 registerMethod = false;
311 }
312 }
313 }
314 else {
315 if (methodJSONWebService != null) {
316 JSONWebServiceMode methodJSONWebServiceMode =
317 methodJSONWebService.mode();
318
319 if (!methodJSONWebServiceMode.equals(
320 JSONWebServiceMode.IGNORE)) {
321
322 registerMethod = true;
323 }
324 }
325 }
326
327 if (registerMethod) {
328 registerJSONWebServiceAction(actionClass, method);
329 }
330 }
331 }
332
333 protected void registerJSONWebServiceAction(
334 Class<?> implementationClass, Method method)
335 throws Exception {
336
337 String path = _jsonWebServiceMappingResolver.resolvePath(
338 implementationClass, method);
339
340 String httpMethod = _jsonWebServiceMappingResolver.resolveHttpMethod(
341 method);
342
343 if (_invalidHttpMethods.contains(httpMethod)) {
344 return;
345 }
346
347 Class<?> utilClass = loadUtilClass(implementationClass);
348
349 try {
350 method = utilClass.getMethod(
351 method.getName(), method.getParameterTypes());
352 }
353 catch (NoSuchMethodException nsme) {
354 return;
355 }
356
357 JSONWebServiceActionsManagerUtil.registerJSONWebServiceAction(
358 _contextPath, method.getDeclaringClass(), method, path, httpMethod);
359
360 _registeredActionsCount++;
361 }
362
363 private static Log _log = LogFactoryUtil.getLog(
364 BaseJSONWebServiceConfigurator.class);
365
366 private static Set<String> _excludedMethodNames = SetUtil.fromArray(
367 new String[] {"getBeanIdentifier", "setBeanIdentifier"});
368
369 private ClassLoader _classLoader;
370 private String _contextPath;
371 private Set<String> _invalidHttpMethods = SetUtil.fromArray(
372 PropsUtil.getArray(PropsKeys.JSONWS_WEB_SERVICE_INVALID_HTTP_METHODS));
373 private final byte[] _jsonWebServiceAnnotationBytes = getTypeSignatureBytes(
374 JSONWebService.class);
375 private JSONWebServiceMappingResolver _jsonWebServiceMappingResolver =
376 new JSONWebServiceMappingResolver();
377 private int _registeredActionsCount;
378 private ServletContext _servletContext;
379 private Map<Class<?>, Class<?>> _utilClasses =
380 new HashMap<Class<?>, Class<?>>();
381
382 }