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