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