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