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