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.security.pacl.PACLClassLoaderUtil;
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.HashMap;
045 import java.util.Map;
046 import java.util.Set;
047
048 import jodd.io.findfile.ClassFinder;
049 import jodd.io.findfile.FindFile;
050 import jodd.io.findfile.RegExpFindFile;
051
052 import jodd.util.ClassLoaderUtil;
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 classPathFiles = new File[2];
130
131 classPathFiles[0] = classPathFile;
132
133 FindFile findFile = new RegExpFindFile(
134 ".*-(hook|portlet|web)-service.*\\.jar");
135
136 findFile.searchPath(libDir);
137
138 classPathFiles[1] = findFile.nextFile();
139
140 if (classPathFiles[1] == null) {
141 File classesDir = new File(libDir.getParent(), "classes");
142
143 classPathFiles[1] = classesDir;
144 }
145 }
146 else {
147 classLoader = PACLClassLoaderUtil.getContextClassLoader();
148
149 File portalImplJarFile = new File(
150 PortalUtil.getPortalLibDir(), "portal-impl.jar");
151 File portalServiceJarFile = new File(
152 PortalUtil.getGlobalLibDir(), "portal-service.jar");
153
154 if (portalImplJarFile.exists() && portalServiceJarFile.exists()) {
155 classPathFiles = new File[2];
156
157 classPathFiles[0] = portalImplJarFile;
158 classPathFiles[1] = portalServiceJarFile;
159 }
160 else {
161 classPathFiles = ClassLoaderUtil.getDefaultClasspath(
162 classLoader);
163 }
164 }
165
166 _classLoader = classLoader;
167
168 _configure(classPathFiles);
169 }
170
171 @Override
172 protected void onEntry(EntryData entryData) throws Exception {
173 String className = entryData.getName();
174
175 if (className.endsWith("Service") ||
176 className.endsWith("ServiceImpl")) {
177
178 InputStream inputStream = entryData.openInputStream();
179
180 if (!isTypeSignatureInUse(
181 inputStream, _jsonWebServiceAnnotationBytes)) {
182
183 return;
184 }
185
186 if (!entryData.isArchive()) {
187 StreamUtil.cleanUp(inputStream);
188
189 ClassReader classReader = new ClassReader(
190 entryData.openInputStream());
191
192 JSONWebServiceClassVisitor jsonWebServiceClassVisitor =
193 new JSONWebServiceClassVisitor();
194
195 try {
196 classReader.accept(jsonWebServiceClassVisitor, 0);
197 }
198 catch (Exception e) {
199 return;
200 }
201
202 if (!className.equals(
203 jsonWebServiceClassVisitor.getClassName())) {
204
205 return;
206 }
207 }
208
209 _onJSONWebServiceClass(className);
210 }
211 }
212
213 private void _configure(File... classPathFiles) throws PortalException {
214 StopWatch stopWatch = null;
215
216 if (_log.isDebugEnabled()) {
217 _log.debug("Configure JSON web service actions");
218
219 stopWatch = new StopWatch();
220
221 stopWatch.start();
222 }
223
224 try {
225 scanPaths(classPathFiles);
226 }
227 catch (Exception e) {
228 throw new PortalException(e.getMessage(), e);
229 }
230
231 if (_log.isDebugEnabled()) {
232 _log.debug(
233 "Configured " + _registeredActionsCount + " actions in " +
234 stopWatch.getTime() + " ms");
235 }
236 }
237
238 private boolean _hasAnnotatedServiceImpl(String className) {
239 StringBundler implClassName = new StringBundler(4);
240
241 int pos = className.lastIndexOf(CharPool.PERIOD);
242
243 implClassName.append(className.substring(0, pos));
244 implClassName.append(".impl");
245 implClassName.append(className.substring(pos));
246 implClassName.append("Impl");
247
248 Class<?> implClass = null;
249
250 try {
251 implClass = _classLoader.loadClass(implClassName.toString());
252 }
253 catch (ClassNotFoundException cnfe) {
254 return false;
255 }
256
257 if (implClass.getAnnotation(JSONWebService.class) != null) {
258 return true;
259 }
260 else {
261 return false;
262 }
263 }
264
265 private boolean _isJSONWebServiceClass(Class<?> clazz) {
266 if (!clazz.isAnonymousClass() && !clazz.isArray() && !clazz.isEnum() &&
267 !clazz.isLocalClass() && !clazz.isPrimitive() &&
268 !(clazz.isMemberClass() ^
269 Modifier.isStatic(clazz.getModifiers()))) {
270
271 return true;
272 }
273
274 return false;
275 }
276
277 private Class<?> _loadUtilClass(Class<?> implementationClass)
278 throws ClassNotFoundException {
279
280 Class<?> utilClass = _utilClasses.get(implementationClass);
281
282 if (utilClass != null) {
283 return utilClass;
284 }
285
286 String utilClassName = implementationClass.getName();
287
288 if (utilClassName.endsWith("Impl")) {
289 utilClassName = utilClassName.substring(
290 0, utilClassName.length() - 4);
291
292 }
293
294 utilClassName += "Util";
295
296 utilClassName = StringUtil.replace(utilClassName, ".impl.", ".");
297
298 utilClass = _classLoader.loadClass(utilClassName);
299
300 _utilClasses.put(implementationClass, utilClass);
301
302 return utilClass;
303 }
304
305 private void _onJSONWebServiceClass(String className) throws Exception {
306 Class<?> actionClass = _classLoader.loadClass(className);
307
308 if (!_isJSONWebServiceClass(actionClass)) {
309 return;
310 }
311
312 if (actionClass.isInterface() && _hasAnnotatedServiceImpl(className)) {
313 return;
314 }
315
316 JSONWebService classAnnotation = actionClass.getAnnotation(
317 JSONWebService.class);
318
319 JSONWebServiceMode classAnnotationMode = JSONWebServiceMode.MANUAL;
320
321 if (classAnnotation != null) {
322 classAnnotationMode = classAnnotation.mode();
323 }
324
325 Method[] methods = actionClass.getMethods();
326
327 for (Method method : methods) {
328 Class<?> methodDeclaringClass = method.getDeclaringClass();
329
330 if (!methodDeclaringClass.equals(actionClass)) {
331 continue;
332 }
333
334 boolean registerMethod = false;
335
336 JSONWebService methodAnnotation = method.getAnnotation(
337 JSONWebService.class);
338
339 if (classAnnotationMode.equals(JSONWebServiceMode.AUTO)) {
340 registerMethod = true;
341
342 if (methodAnnotation != null) {
343 JSONWebServiceMode methodAnnotationMode =
344 methodAnnotation.mode();
345
346 if (methodAnnotationMode.equals(
347 JSONWebServiceMode.IGNORE)) {
348
349 registerMethod = false;
350 }
351 }
352 }
353 else {
354 if (methodAnnotation != null) {
355 JSONWebServiceMode methodAnnotationMode =
356 methodAnnotation.mode();
357
358 if (!methodAnnotationMode.equals(
359 JSONWebServiceMode.IGNORE)) {
360
361 registerMethod = true;
362 }
363 }
364 }
365
366 if ((_excludedMethodNames != null) &&
367 _excludedMethodNames.contains(method.getName())) {
368
369 registerMethod = false;
370 }
371
372 if (registerMethod) {
373 _registerJSONWebServiceAction(actionClass, method);
374 }
375 }
376 }
377
378 private void _registerJSONWebServiceAction(
379 Class<?> implementationClass, Method method)
380 throws Exception {
381
382 String path = _jsonWebServiceMappingResolver.resolvePath(
383 implementationClass, method);
384
385 String httpMethod = _jsonWebServiceMappingResolver.resolveHttpMethod(
386 method);
387
388 if (_invalidHttpMethods.contains(httpMethod)) {
389 return;
390 }
391
392 Class<?> utilClass = _loadUtilClass(implementationClass);
393
394 try {
395 method = utilClass.getMethod(
396 method.getName(), method.getParameterTypes());
397 }
398 catch (NoSuchMethodException nsme) {
399 return;
400 }
401
402 JSONWebServiceActionsManagerUtil.registerJSONWebServiceAction(
403 _servletContextPath, method.getDeclaringClass(), method, path,
404 httpMethod);
405
406 _registeredActionsCount++;
407 }
408
409 private static Log _log = LogFactoryUtil.getLog(
410 JSONWebServiceConfigurator.class);
411
412 private static Set<String> _excludedMethodNames = SetUtil.fromArray(
413 new String[] {"getBeanIdentifier", "setBeanIdentifier"});
414
415 private ClassLoader _classLoader;
416 private Set<String> _invalidHttpMethods = SetUtil.fromArray(
417 PropsValues.JSONWS_WEB_SERVICE_INVALID_HTTP_METHODS);
418 private byte[] _jsonWebServiceAnnotationBytes = getTypeSignatureBytes(
419 JSONWebService.class);
420 private JSONWebServiceMappingResolver _jsonWebServiceMappingResolver =
421 new JSONWebServiceMappingResolver();
422 private int _registeredActionsCount;
423 private String _servletContextPath;
424 private Map<Class<?>, Class<?>> _utilClasses =
425 new HashMap<Class<?>, Class<?>>();
426
427 }