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