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