001
014
015 package com.liferay.portal.jsonwebservice;
016
017 import com.liferay.portal.kernel.exception.PortalException;
018 import com.liferay.portal.kernel.exception.SystemException;
019 import com.liferay.portal.kernel.jsonwebservice.JSONWebService;
020 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionsManagerUtil;
021 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceMode;
022 import com.liferay.portal.kernel.log.Log;
023 import com.liferay.portal.kernel.log.LogFactoryUtil;
024 import com.liferay.portal.kernel.util.CharPool;
025 import com.liferay.portal.kernel.util.SetUtil;
026 import com.liferay.portal.kernel.util.StreamUtil;
027 import com.liferay.portal.kernel.util.StringBundler;
028 import com.liferay.portal.kernel.util.StringPool;
029 import com.liferay.portal.kernel.util.StringUtil;
030 import com.liferay.portal.util.ClassLoaderUtil;
031 import com.liferay.portal.util.PortalUtil;
032 import com.liferay.portal.util.PropsValues;
033
034 import java.io.File;
035 import java.io.InputStream;
036 import java.io.UnsupportedEncodingException;
037
038 import java.lang.reflect.Method;
039 import java.lang.reflect.Modifier;
040
041 import java.net.URL;
042 import java.net.URLDecoder;
043
044 import java.util.ArrayList;
045 import java.util.HashMap;
046 import java.util.List;
047 import java.util.Map;
048 import java.util.Set;
049
050 import jodd.io.findfile.ClassFinder;
051 import jodd.io.findfile.FindFile;
052 import jodd.io.findfile.RegExpFindFile;
053
054 import org.apache.commons.lang.time.StopWatch;
055
056 import org.objectweb.asm.ClassReader;
057
058
061 public class JSONWebServiceConfigurator extends ClassFinder {
062
063 public JSONWebServiceConfigurator(String servletContextPath) {
064 setIncludedJars(
065 "*_wl_cls_gen.jar", "*-hook-service*.jar", "*-portlet-service*.jar",
066 "*-web-service*.jar", "*portal-impl.jar", "*portal-service.jar");
067
068 _servletContextPath = servletContextPath;
069 }
070
071 public void clean() {
072 int count =
073 JSONWebServiceActionsManagerUtil.unregisterJSONWebServiceActions(
074 _servletContextPath);
075
076 _registeredActionsCount -= count;
077
078 if (_log.isDebugEnabled()) {
079 if (count != 0) {
080 _log.debug(
081 "Removed " + count +
082 " existing JSON Web Service actions that belonged to " +
083 _servletContextPath);
084 }
085 }
086 }
087
088 public void configure(ClassLoader classLoader)
089 throws PortalException, SystemException {
090
091 File[] classPathFiles = null;
092
093 if (classLoader != null) {
094 URL servicePropertiesURL = classLoader.getResource(
095 "service.properties");
096
097 String servicePropertiesPath = null;
098
099 try {
100 servicePropertiesPath = URLDecoder.decode(
101 servicePropertiesURL.getPath(), StringPool.UTF8);
102 }
103 catch (UnsupportedEncodingException uee) {
104 throw new SystemException(uee);
105 }
106
107 File classPathFile = null;
108
109 File libDir = null;
110
111 int pos = servicePropertiesPath.indexOf("_wl_cls_gen.jar!");
112
113 if (pos != -1) {
114 String wlClsGenJarPath = servicePropertiesPath.substring(
115 0, pos + 15);
116
117 classPathFile = new File(wlClsGenJarPath);
118
119 libDir = new File(classPathFile.getParent());
120 }
121 else {
122 File servicePropertiesFile = new File(servicePropertiesPath);
123
124 classPathFile = servicePropertiesFile.getParentFile();
125
126 libDir = new File(classPathFile.getParent(), "lib");
127 }
128
129 List<File> classPaths = new ArrayList<File>();
130
131 classPaths.add(classPathFile);
132
133 FindFile findFile = new RegExpFindFile(
134 ".*-(hook|portlet|web)-service.*\\.jar");
135
136 findFile.searchPath(libDir);
137
138 File file = null;
139
140 while ((file = findFile.nextFile()) != null) {
141 classPaths.add(file);
142 }
143
144 File classesDir = new File(libDir.getParent(), "classes");
145
146 classPaths.add(classesDir);
147
148 classPathFiles = classPaths.toArray(new File[classPaths.size()]);
149 }
150 else {
151 classLoader = ClassLoaderUtil.getContextClassLoader();
152
153 File portalImplJarFile = new File(
154 PortalUtil.getPortalLibDir(), "portal-impl.jar");
155 File portalServiceJarFile = new File(
156 PortalUtil.getGlobalLibDir(), "portal-service.jar");
157
158 if (portalImplJarFile.exists() && portalServiceJarFile.exists()) {
159 classPathFiles = new File[2];
160
161 classPathFiles[0] = portalImplJarFile;
162 classPathFiles[1] = portalServiceJarFile;
163 }
164 else {
165 classPathFiles = jodd.util.ClassLoaderUtil.getDefaultClasspath(
166 classLoader);
167 }
168 }
169
170 _classLoader = classLoader;
171
172 _configure(classPathFiles);
173 }
174
175 @Override
176 protected void onEntry(EntryData entryData) throws Exception {
177 String className = entryData.getName();
178
179 if (className.endsWith("Service") ||
180 className.endsWith("ServiceImpl")) {
181
182 InputStream inputStream = entryData.openInputStream();
183
184 if (!isTypeSignatureInUse(
185 inputStream, _jsonWebServiceAnnotationBytes)) {
186
187 return;
188 }
189
190 if (!entryData.isArchive()) {
191 StreamUtil.cleanUp(inputStream);
192
193 ClassReader classReader = new ClassReader(
194 entryData.openInputStream());
195
196 JSONWebServiceClassVisitor jsonWebServiceClassVisitor =
197 new JSONWebServiceClassVisitor();
198
199 try {
200 classReader.accept(jsonWebServiceClassVisitor, 0);
201 }
202 catch (Exception e) {
203 return;
204 }
205
206 if (!className.equals(
207 jsonWebServiceClassVisitor.getClassName())) {
208
209 return;
210 }
211 }
212
213 _onJSONWebServiceClass(className);
214 }
215 }
216
217 private void _configure(File... classPathFiles) throws PortalException {
218 StopWatch stopWatch = null;
219
220 if (_log.isDebugEnabled()) {
221 _log.debug("Configure JSON web service actions");
222
223 stopWatch = new StopWatch();
224
225 stopWatch.start();
226 }
227
228 try {
229 scanPaths(classPathFiles);
230 }
231 catch (Exception e) {
232 throw new PortalException(e.getMessage(), e);
233 }
234
235 if (_log.isDebugEnabled()) {
236 _log.debug(
237 "Configured " + _registeredActionsCount + " actions in " +
238 stopWatch.getTime() + " ms");
239 }
240 }
241
242 private boolean _hasAnnotatedServiceImpl(String className) {
243 StringBundler implClassName = new StringBundler(4);
244
245 int pos = className.lastIndexOf(CharPool.PERIOD);
246
247 implClassName.append(className.substring(0, pos));
248 implClassName.append(".impl");
249 implClassName.append(className.substring(pos));
250 implClassName.append("Impl");
251
252 Class<?> implClass = null;
253
254 try {
255 implClass = _classLoader.loadClass(implClassName.toString());
256 }
257 catch (ClassNotFoundException cnfe) {
258 return false;
259 }
260
261 if (implClass.getAnnotation(JSONWebService.class) != null) {
262 return true;
263 }
264 else {
265 return false;
266 }
267 }
268
269 private boolean _isJSONWebServiceClass(Class<?> clazz) {
270 if (!clazz.isAnonymousClass() && !clazz.isArray() && !clazz.isEnum() &&
271 !clazz.isLocalClass() && !clazz.isPrimitive() &&
272 !(clazz.isMemberClass() ^
273 Modifier.isStatic(clazz.getModifiers()))) {
274
275 return true;
276 }
277
278 return false;
279 }
280
281 private Class<?> _loadUtilClass(Class<?> implementationClass)
282 throws ClassNotFoundException {
283
284 Class<?> utilClass = _utilClasses.get(implementationClass);
285
286 if (utilClass != null) {
287 return utilClass;
288 }
289
290 String utilClassName = implementationClass.getName();
291
292 if (utilClassName.endsWith("Impl")) {
293 utilClassName = utilClassName.substring(
294 0, utilClassName.length() - 4);
295
296 }
297
298 utilClassName += "Util";
299
300 utilClassName = StringUtil.replace(utilClassName, ".impl.", ".");
301
302 utilClass = _classLoader.loadClass(utilClassName);
303
304 _utilClasses.put(implementationClass, utilClass);
305
306 return utilClass;
307 }
308
309 private void _onJSONWebServiceClass(String className) throws Exception {
310 Class<?> actionClass = _classLoader.loadClass(className);
311
312 if (!_isJSONWebServiceClass(actionClass)) {
313 return;
314 }
315
316 if (actionClass.isInterface() && _hasAnnotatedServiceImpl(className)) {
317 return;
318 }
319
320 JSONWebService classAnnotation = actionClass.getAnnotation(
321 JSONWebService.class);
322
323 JSONWebServiceMode classAnnotationMode = JSONWebServiceMode.MANUAL;
324
325 if (classAnnotation != null) {
326 classAnnotationMode = classAnnotation.mode();
327 }
328
329 Method[] methods = actionClass.getMethods();
330
331 for (Method method : methods) {
332 Class<?> methodDeclaringClass = method.getDeclaringClass();
333
334 if (!methodDeclaringClass.equals(actionClass)) {
335 continue;
336 }
337
338 if ((_excludedMethodNames != null) &&
339 _excludedMethodNames.contains(method.getName())) {
340
341 continue;
342 }
343
344 boolean registerMethod = false;
345
346 JSONWebService methodAnnotation = method.getAnnotation(
347 JSONWebService.class);
348
349 if (classAnnotationMode.equals(JSONWebServiceMode.AUTO)) {
350 registerMethod = true;
351
352 if (methodAnnotation != null) {
353 JSONWebServiceMode methodAnnotationMode =
354 methodAnnotation.mode();
355
356 if (methodAnnotationMode.equals(
357 JSONWebServiceMode.IGNORE)) {
358
359 registerMethod = false;
360 }
361 }
362 }
363 else {
364 if (methodAnnotation != null) {
365 JSONWebServiceMode methodAnnotationMode =
366 methodAnnotation.mode();
367
368 if (!methodAnnotationMode.equals(
369 JSONWebServiceMode.IGNORE)) {
370
371 registerMethod = true;
372 }
373 }
374 }
375
376 if (registerMethod) {
377 _registerJSONWebServiceAction(actionClass, method);
378 }
379 }
380 }
381
382 private void _registerJSONWebServiceAction(
383 Class<?> implementationClass, Method method)
384 throws Exception {
385
386 String path = _jsonWebServiceMappingResolver.resolvePath(
387 implementationClass, method);
388
389 String httpMethod = _jsonWebServiceMappingResolver.resolveHttpMethod(
390 method);
391
392 if (_invalidHttpMethods.contains(httpMethod)) {
393 return;
394 }
395
396 Class<?> utilClass = _loadUtilClass(implementationClass);
397
398 try {
399 method = utilClass.getMethod(
400 method.getName(), method.getParameterTypes());
401 }
402 catch (NoSuchMethodException nsme) {
403 return;
404 }
405
406 JSONWebServiceActionsManagerUtil.registerJSONWebServiceAction(
407 _servletContextPath, method.getDeclaringClass(), method, path,
408 httpMethod);
409
410 _registeredActionsCount++;
411 }
412
413 private static Log _log = LogFactoryUtil.getLog(
414 JSONWebServiceConfigurator.class);
415
416 private static Set<String> _excludedMethodNames = SetUtil.fromArray(
417 new String[] {"getBeanIdentifier", "setBeanIdentifier"});
418
419 private ClassLoader _classLoader;
420 private Set<String> _invalidHttpMethods = SetUtil.fromArray(
421 PropsValues.JSONWS_WEB_SERVICE_INVALID_HTTP_METHODS);
422 private byte[] _jsonWebServiceAnnotationBytes = getTypeSignatureBytes(
423 JSONWebService.class);
424 private JSONWebServiceMappingResolver _jsonWebServiceMappingResolver =
425 new JSONWebServiceMappingResolver();
426 private int _registeredActionsCount;
427 private String _servletContextPath;
428 private Map<Class<?>, Class<?>> _utilClasses =
429 new HashMap<Class<?>, Class<?>>();
430
431 }