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.PortalUtil;
031 import com.liferay.portal.util.PropsValues;
032
033 import java.io.File;
034 import java.io.InputStream;
035 import java.io.UnsupportedEncodingException;
036
037 import java.lang.reflect.Method;
038 import java.lang.reflect.Modifier;
039
040 import java.net.URL;
041 import java.net.URLDecoder;
042
043 import java.util.HashMap;
044 import java.util.Map;
045 import java.util.Set;
046
047 import jodd.io.findfile.ClassFinder;
048 import jodd.io.findfile.FindFile;
049 import jodd.io.findfile.WildcardFindFile;
050
051 import jodd.util.ClassLoaderUtil;
052
053 import org.apache.commons.lang.time.StopWatch;
054
055 import org.objectweb.asm.ClassReader;
056
057
060 public class JSONWebServiceConfigurator extends ClassFinder {
061
062 public JSONWebServiceConfigurator(String servletContextPath) {
063 setIncludedJars(
064 "*portal-impl.jar", "*portal-service.jar", "*_wl_cls_gen.jar",
065 "*-portlet-service*.jar");
066
067 _servletContextPath = servletContextPath;
068 }
069
070 public void clean() {
071 int count =
072 JSONWebServiceActionsManagerUtil.unregisterJSONWebServiceActions(
073 _servletContextPath);
074
075 _registeredActionsCount -= count;
076
077 if (_log.isDebugEnabled()) {
078 if (count != 0) {
079 _log.debug(
080 "Removed " + count +
081 " existing JSON Web Service actions that belonged to " +
082 _servletContextPath);
083 }
084 }
085 }
086
087 public void configure(ClassLoader classLoader)
088 throws PortalException, SystemException {
089
090 File[] classPathFiles = null;
091
092 if (classLoader != null) {
093 URL servicePropertiesURL = classLoader.getResource(
094 "service.properties");
095
096 String servicePropertiesPath = null;
097
098 try {
099 servicePropertiesPath = URLDecoder.decode(
100 servicePropertiesURL.getPath(), StringPool.UTF8);
101 }
102 catch (UnsupportedEncodingException uee) {
103 throw new SystemException(uee);
104 }
105
106 File classPathFile = null;
107
108 File libDir = null;
109
110 int pos = servicePropertiesPath.indexOf("_wl_cls_gen.jar!");
111
112 if (pos != -1) {
113 String wlClsGenJarPath = servicePropertiesPath.substring(
114 0, pos + 15);
115
116 classPathFile = new File(wlClsGenJarPath);
117
118 libDir = new File(classPathFile.getParent());
119 }
120 else {
121 File servicePropertiesFile = new File(servicePropertiesPath);
122
123 classPathFile = servicePropertiesFile.getParentFile();
124
125 libDir = new File(classPathFile.getParent(), "lib");
126 }
127
128 classPathFiles = new File[2];
129
130 classPathFiles[0] = classPathFile;
131
132 FindFile findFile = new WildcardFindFile("*-portlet-service*.jar");
133
134 findFile.searchPath(libDir);
135
136 classPathFiles[1] = findFile.nextFile();
137
138 if (classPathFiles[1] == null) {
139 File classesDir = new File(libDir.getParent(), "classes");
140
141 classPathFiles[1] = classesDir;
142 }
143 }
144 else {
145 Thread currentThread = Thread.currentThread();
146
147 classLoader = currentThread.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 (registerMethod) {
367 _registerJSONWebServiceAction(actionClass, method);
368 }
369 }
370 }
371
372 private void _registerJSONWebServiceAction(
373 Class<?> implementationClass, Method method)
374 throws Exception {
375
376 String path = _jsonWebServiceMappingResolver.resolvePath(
377 implementationClass, method);
378
379 String httpMethod = _jsonWebServiceMappingResolver.resolveHttpMethod(
380 method);
381
382 if (_invalidHttpMethods.contains(httpMethod)) {
383 return;
384 }
385
386 Class<?> utilClass = _loadUtilClass(implementationClass);
387
388 try {
389 method = utilClass.getMethod(
390 method.getName(), method.getParameterTypes());
391 }
392 catch (NoSuchMethodException nsme) {
393 return;
394 }
395
396 JSONWebServiceActionsManagerUtil.registerJSONWebServiceAction(
397 _servletContextPath, method.getDeclaringClass(), method, path,
398 httpMethod);
399
400 _registeredActionsCount++;
401 }
402
403 private static Log _log = LogFactoryUtil.getLog(
404 JSONWebServiceConfigurator.class);
405
406 private ClassLoader _classLoader;
407 private Set<String> _invalidHttpMethods = SetUtil.fromArray(
408 PropsValues.JSONWS_WEB_SERVICE_INVALID_HTTP_METHODS);
409 private byte[] _jsonWebServiceAnnotationBytes =
410 getTypeSignatureBytes(JSONWebService.class);
411 private JSONWebServiceMappingResolver _jsonWebServiceMappingResolver =
412 new JSONWebServiceMappingResolver();
413 private int _registeredActionsCount;
414 private String _servletContextPath;
415 private Map<Class<?>, Class<?>> _utilClasses =
416 new HashMap<Class<?>, Class<?>>();
417
418 }