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