001package org.apache.maven.tools.plugin.extractor.annotations.converter.tag;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.Optional;
023import java.util.function.UnaryOperator;
024
025import org.apache.maven.tools.plugin.extractor.annotations.converter.ConverterContext;
026import org.apache.maven.tools.plugin.javadoc.FullyQualifiedJavadocReference;
027import org.apache.maven.tools.plugin.javadoc.JavadocReference;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030
031/**
032 * Utility methods for dealing with links generated from Javadoc tags.
033 */
034public class LinkUtils
035{
036
037    private static final Logger LOG = LoggerFactory.getLogger( LinkUtils.class );
038
039    private LinkUtils()
040    {
041        // only static methods
042    }
043
044    public static String createLink( String referenceValue, ConverterContext context )
045    {
046        return createLink( referenceValue, context, UnaryOperator.identity() );
047    }
048
049    public static String createLink( String referenceValue, ConverterContext context,
050                                     UnaryOperator<String> labelDecorator )
051    {
052        try
053        {
054            JavadocReference reference = JavadocReference.parse( referenceValue );
055            FullyQualifiedJavadocReference fqReference = context.resolveReference( reference );
056            if ( !context.canGetUrl() )
057            {
058                return getReferenceLabel( fqReference, context, labelDecorator, "no javadoc sites associated" );
059            }
060            return createLink( referenceValue, fqReference, context, labelDecorator );
061        }
062        catch ( IllegalArgumentException e )
063        {
064            LOG.warn( "Unresolvable link in javadoc tag with value {} found in {}: {}", referenceValue,
065                      context.getLocation(), e.getMessage() );
066            return labelDecorator.apply( referenceValue ) + "<!-- this link could not be resolved -->";
067        }
068    }
069
070    private static String createLink( String referenceValue, FullyQualifiedJavadocReference fqReference, 
071                                      ConverterContext context, UnaryOperator<String> labelDecorator )
072    {
073        StringBuilder link = new StringBuilder();
074        try
075        {
076            link.append( "<a href=\"" );
077            link.append( context.getUrl( fqReference ).toString() );
078            link.append( "\">" );
079            String label = getReferenceLabel( fqReference, context );
080            label = labelDecorator.apply( label );
081            link.append( label );
082            link.append( "</a>" );
083        }
084        catch ( IllegalArgumentException e )
085        {
086            LOG.warn( "Could not get javadoc URL for reference {} at {} (fully qualified {}): {}", referenceValue,
087                      fqReference, context.getLocation(), e.getMessage() );
088            return getReferenceLabel( fqReference, context, labelDecorator,
089                                      "reference not found in associated javadoc sites" );
090        }
091        return link.toString();
092    }
093
094    private static String getReferenceLabel( FullyQualifiedJavadocReference fqReference, ConverterContext context,
095                                      UnaryOperator<String> labelDecorator, String htmlComment ) 
096    {
097        String label = getReferenceLabel( fqReference, context );
098        return labelDecorator.apply( label ) + "<!-- " + htmlComment + " -->";
099    }
100
101    /**
102     * @return the undecorated label of the link
103     * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#JSWOR656"> javadoc: How
104     *      a Name Appears</a>
105     */
106    private static String getReferenceLabel( FullyQualifiedJavadocReference fqReference, ConverterContext context )
107    {
108        if ( fqReference.getLabel().isPresent() )
109        {
110            return fqReference.getLabel().get();
111        }
112        else
113        {
114            Optional<String> packageName;
115            Optional<String> moduleName;
116            Optional<String> className = fqReference.getClassName();
117            if ( Optional.of( context.getPackageName() ).equals( fqReference.getPackageName() )
118                && context.getModuleName().equals( fqReference.getModuleName() ) )
119            {
120                packageName = Optional.empty();
121                moduleName = Optional.empty();
122                if ( context.isReferencedBy( fqReference ) )
123                {
124                    className = Optional.empty();
125                }
126            }
127            else
128            {
129                packageName = fqReference.getPackageName();
130                moduleName = fqReference.getModuleName();
131            }
132            return createLabel( moduleName, packageName, className, fqReference.getMember() );
133        }
134    }
135
136    private static String createLabel( Optional<String> moduleName, Optional<String> packageName,
137                                       Optional<String> className, Optional<String> member )
138    {
139        StringBuilder sb = new StringBuilder();
140        if ( packageName.isPresent() && !"java.lang".equals( packageName.get() ) )
141        {
142            sb.append( packageName.get() );
143        }
144        if ( className.isPresent() )
145        {
146            if ( sb.length() > 0 )
147            {
148                sb.append( '.' );
149            }
150            sb.append( className.get() );
151        }
152        if ( member.isPresent() )
153        {
154            if ( sb.length() > 0 )
155            {
156                sb.append( '.' );
157            }
158            sb.append( member.get() );
159        }
160        return sb.toString();
161    }
162
163}