001package ball.tools.javadoc;
002/*-
003 * ##########################################################################
004 * Utilities
005 * $Id: IncludeTaglet.java 6035 2020-05-25 03:01:46Z ball $
006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/ball-util/trunk/src/main/java/ball/tools/javadoc/IncludeTaglet.java $
007 * %%
008 * Copyright (C) 2008 - 2020 Allen D. Ball
009 * %%
010 * Licensed under the Apache License, Version 2.0 (the "License");
011 * you may not use this file except in compliance with the License.
012 * You may obtain a copy of the License at
013 *
014 *      http://www.apache.org/licenses/LICENSE-2.0
015 *
016 * Unless required by applicable law or agreed to in writing, software
017 * distributed under the License is distributed on an "AS IS" BASIS,
018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019 * See the License for the specific language governing permissions and
020 * limitations under the License.
021 * ##########################################################################
022 */
023import ball.annotation.ServiceProviderFor;
024import ball.swing.table.ListTableModel;
025import ball.swing.table.MapTableModel;
026import ball.xml.FluentNode;
027import com.sun.javadoc.ClassDoc;
028import com.sun.javadoc.Tag;
029import com.sun.tools.doclets.Taglet;
030import java.io.InputStream;
031import java.util.Collection;
032import java.util.Map;
033import java.util.regex.Pattern;
034import java.util.stream.Collectors;
035import lombok.NoArgsConstructor;
036import lombok.ToString;
037import org.apache.commons.io.IOUtils;
038
039import static org.apache.commons.lang3.StringUtils.isNotEmpty;
040
041/**
042 * Inline {@link Taglet} to include a static {@link Class}
043 * {@link java.lang.reflect.Field} or resource in the Javadoc output.
044 *
045 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
046 * @version $Revision: 6035 $
047 */
048@ServiceProviderFor({ Taglet.class })
049@TagletName("include")
050@NoArgsConstructor @ToString
051public class IncludeTaglet extends AbstractInlineTaglet
052                           implements SunToolsInternalToolkitTaglet {
053    private static final IncludeTaglet INSTANCE = new IncludeTaglet();
054
055    public static void register(Map<Object,Object> map) {
056        register(map, INSTANCE);
057    }
058
059    @Override
060    public FluentNode toNode(Tag tag) throws Throwable {
061        FluentNode node = null;
062        String[] text = tag.text().trim().split(Pattern.quote("#"), 2);
063
064        if (text.length > 1) {
065            node =
066                field(tag,
067                      getClassFor(isNotEmpty(text[0])
068                                      ? getClassDocFor(tag, text[0])
069                                      : containingClass(tag)),
070                      text[1]);
071        } else {
072            node =
073                resource(tag,
074                         getClassFor(containingClass(tag)),
075                         text[0]);
076        }
077
078        return node;
079    }
080
081    private FluentNode field(Tag tag,
082                             Class<?> type, String name) throws Exception {
083        Object object = type.getField(name).get(null);
084        FluentNode node = null;
085
086        if (object instanceof Collection<?>) {
087            node =
088                table(tag,
089                      new ListTableModel(((Collection<?>) object)
090                                         .stream()
091                                         .collect(Collectors.toList()),
092                                         "Element"));
093        } else if (object instanceof Map<?,?>) {
094            node =
095                table(tag,
096                      new MapTableModel((Map<?,?>) object, "Key", "Value"));
097        } else {
098            node = pre(String.valueOf(object));
099        }
100
101        return div(attr("class", "block"), node);
102    }
103
104    private FluentNode resource(Tag tag,
105                                Class<?> type, String name) throws Exception {
106        String string = null;
107
108        if (type == null) {
109            type = getClass();
110        }
111
112        try (InputStream in = type.getResourceAsStream(name)) {
113            string = IOUtils.toString(in, "UTF-8");
114        }
115
116        return pre(string);
117    }
118}