001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.javadoc;
016    
017    import com.liferay.portal.kernel.javadoc.BaseJavadoc;
018    import com.liferay.portal.kernel.javadoc.JavadocClass;
019    import com.liferay.portal.kernel.javadoc.JavadocManager;
020    import com.liferay.portal.kernel.javadoc.JavadocMethod;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
024    import com.liferay.portal.kernel.util.StreamUtil;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.kernel.xml.Document;
027    import com.liferay.portal.kernel.xml.Element;
028    import com.liferay.portal.kernel.xml.SAXReaderUtil;
029    import com.liferay.portal.util.PropsValues;
030    
031    import java.io.InputStream;
032    
033    import java.lang.reflect.Method;
034    
035    import java.net.URL;
036    
037    import java.util.Collection;
038    import java.util.HashMap;
039    import java.util.Iterator;
040    import java.util.List;
041    import java.util.Map;
042    
043    /**
044     * @author Igor Spasic
045     */
046    @DoPrivileged
047    public class JavadocManagerImpl implements JavadocManager {
048    
049            @Override
050            public void load(String servletContextName, ClassLoader classLoader) {
051                    if (!PropsValues.JAVADOC_MANAGER_ENABLED) {
052                            return;
053                    }
054    
055                    if (_log.isInfoEnabled()) {
056                            _log.info("Loading Javadocs for \"" + servletContextName + '\"');
057                    }
058    
059                    Document document = getDocument(classLoader);
060    
061                    if (document == null) {
062                            return;
063                    }
064    
065                    parseDocument(servletContextName, classLoader, document);
066    
067                    if (_log.isInfoEnabled()) {
068                            _log.info("Loaded Javadocs for \"" + servletContextName + '\"');
069                    }
070            }
071    
072            @Override
073            public JavadocMethod lookupJavadocMethod(Method method) {
074                    JavadocMethod javadocMethod = _javadocMethods.get(method);
075    
076                    if (javadocMethod != null) {
077                            return javadocMethod;
078                    }
079    
080                    Class<?> clazz = method.getDeclaringClass();
081    
082                    String className = clazz.getName();
083    
084                    if (!className.contains(".service.") ||
085                            !className.endsWith("ServiceUtil")) {
086    
087                            return null;
088                    }
089    
090                    String implClassName = StringUtil.replace(
091                            className, new String[] {".service.", "ServiceUtil"},
092                            new String[] {".service.impl.", "ServiceImpl"});
093    
094                    if (_log.isDebugEnabled()) {
095                            _log.debug(
096                                    "Attempting to load method from class " + implClassName +
097                                            " instead of " + className);
098                    }
099    
100                    try {
101                            Class<?> implClass = JavadocUtil.loadClass(
102                                    clazz.getClassLoader(), implClassName);
103    
104                            Method implMethod = implClass.getMethod(
105                                    method.getName(), method.getParameterTypes());
106    
107                            return _javadocMethods.get(implMethod);
108                    }
109                    catch (NoSuchMethodException nsme) {
110                            if (_log.isWarnEnabled()) {
111                                    _log.warn(
112                                            "Unable to load method " + method.getName() +
113                                                    " from class " + implClassName);
114                            }
115                    }
116                    catch (Exception e) {
117                            if (_log.isWarnEnabled()) {
118                                    _log.warn(
119                                            "Unable to load implementation class " + implClassName);
120                            }
121                    }
122    
123                    return null;
124            }
125    
126            @Override
127            public void unload(String servletContextName) {
128                    if (_log.isInfoEnabled()) {
129                            _log.info("Unloading Javadocs for \"" + servletContextName + '\"');
130                    }
131    
132                    unload(servletContextName, _javadocClasses.values());
133                    unload(servletContextName, _javadocMethods.values());
134    
135                    if (_log.isInfoEnabled()) {
136                            _log.info("Unloaded Javadocs for \"" + servletContextName + '\"');
137                    }
138            }
139    
140            protected Document getDocument(ClassLoader classLoader) {
141                    InputStream inputStream = null;
142    
143                    try {
144                            URL url = classLoader.getResource("META-INF/javadocs-rt.xml");
145    
146                            if (url == null) {
147                                    return null;
148                            }
149    
150                            inputStream = url.openStream();
151    
152                            return SAXReaderUtil.read(inputStream, true);
153                    }
154                    catch (Exception e) {
155                            _log.error(e, e);
156                    }
157                    finally {
158                            StreamUtil.cleanUp(inputStream);
159                    }
160    
161                    return null;
162            }
163    
164            protected void parseDocument(
165                    String servletContextName, ClassLoader classLoader, Document document) {
166    
167                    Element rootElement = document.getRootElement();
168    
169                    List<Element> javadocElements = rootElement.elements("javadoc");
170    
171                    for (Element javadocElement : javadocElements) {
172                            String type = javadocElement.elementText("type");
173    
174                            Class<?> clazz = null;
175    
176                            try {
177                                    clazz = JavadocUtil.loadClass(classLoader, type);
178                            }
179                            catch (ClassNotFoundException cnfe) {
180                                    if (_log.isWarnEnabled()) {
181                                            _log.warn("Unable to load class " + type);
182                                    }
183    
184                                    continue;
185                            }
186    
187                            JavadocClass javadocClass = parseJavadocClass(
188                                    servletContextName, javadocElement, clazz);
189    
190                            _javadocClasses.put(clazz, javadocClass);
191    
192                            List<Element> methodElements = javadocElement.elements("method");
193    
194                            for (Element methodElement : methodElements) {
195                                    try {
196                                            JavadocMethod javadocMethod = parseJavadocMethod(
197                                                    servletContextName, clazz, methodElement);
198    
199                                            _javadocMethods.put(
200                                                    javadocMethod.getMethod(), javadocMethod);
201                                    }
202                                    catch (Exception e) {
203                                            String methodName = methodElement.elementText("name");
204    
205                                            if (_log.isWarnEnabled()) {
206                                                    _log.warn(
207                                                            "Unable to load method " + methodName +
208                                                                    " from class " + type);
209                                            }
210                                    }
211                            }
212                    }
213            }
214    
215            protected JavadocClass parseJavadocClass(
216                    String servletContextName, Element javadocElement, Class<?> clazz) {
217    
218                    JavadocClass javadocClass = new JavadocClass(clazz);
219    
220                    List<Element> authorElements = javadocElement.elements("author");
221    
222                    String[] authors = new String[authorElements.size()];
223    
224                    for (int i = 0; i < authorElements.size(); i++) {
225                            Element authorElement = authorElements.get(i);
226    
227                            authors[i] = authorElement.getText();
228                    }
229    
230                    javadocClass.setAuthors(authors);
231    
232                    String comment = javadocElement.elementText("comment");
233    
234                    javadocClass.setComment(comment);
235    
236                    javadocClass.setServletContextName(servletContextName);
237    
238                    return javadocClass;
239            }
240    
241            protected JavadocMethod parseJavadocMethod(
242                            String servletContextName, Class<?> clazz, Element methodElement)
243                    throws Exception {
244    
245                    String name = methodElement.elementText("name");
246    
247                    List<Element> paramElements = methodElement.elements("param");
248    
249                    Class<?>[] parameterTypeClasses = new Class<?>[paramElements.size()];
250                    String[] parameterComments = new String[paramElements.size()];
251    
252                    for (int i = 0; i < paramElements.size(); i++) {
253                            Element paramElement = paramElements.get(i);
254    
255                            String parameterType = paramElement.elementText("type");
256    
257                            Class<?> parametarTypeClass = JavadocUtil.loadClass(
258                                    clazz.getClassLoader(), parameterType);
259    
260                            parameterTypeClasses[i] = parametarTypeClass;
261    
262                            String parameterComment = paramElement.elementText("comment");
263    
264                            parameterComments[i] = parameterComment;
265                    }
266    
267                    Method method = clazz.getDeclaredMethod(name, parameterTypeClasses);
268    
269                    JavadocMethod javadocMethod = new JavadocMethod(method);
270    
271                    String comment = methodElement.elementText("comment");
272    
273                    javadocMethod.setComment(comment);
274    
275                    javadocMethod.setParameterComments(parameterComments);
276    
277                    Element returnElement = methodElement.element("return");
278    
279                    if (returnElement != null) {
280                            String returnComment = returnElement.elementText("comment");
281    
282                            javadocMethod.setReturnComment(returnComment);
283                    }
284    
285                    javadocMethod.setServletContextName(servletContextName);
286    
287                    List<Element> throwsElements = methodElement.elements("throws");
288    
289                    String[] throwsComments = new String[throwsElements.size()];
290    
291                    for (int i = 0; i < throwsElements.size(); i++) {
292                            Element throwElement = throwsElements.get(i);
293    
294                            throwsComments[i] = throwElement.elementText("comment");
295                    }
296    
297                    javadocMethod.setThrowsComments(throwsComments);
298    
299                    return javadocMethod;
300            }
301    
302            protected void unload(
303                    String servletContextName,
304                    Collection<? extends BaseJavadoc> collection) {
305    
306                    Iterator<? extends BaseJavadoc> iterator = collection.iterator();
307    
308                    while (iterator.hasNext()) {
309                            BaseJavadoc javadoc = iterator.next();
310    
311                            if (servletContextName.equals(javadoc.getServletContextName())) {
312                                    iterator.remove();
313                            }
314                    }
315            }
316    
317            private static Log _log = LogFactoryUtil.getLog(JavadocManagerImpl.class);
318    
319            private Map<Class<?>, JavadocClass> _javadocClasses =
320                    new HashMap<Class<?>, JavadocClass>();
321            private Map<Method, JavadocMethod> _javadocMethods =
322                    new HashMap<Method, JavadocMethod>();
323    
324    }