001package org.apache.maven.tools.plugin.javadoc;
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.Objects;
023import java.util.Optional;
024
025/**
026 * Wraps a fully qualified (and resolved) code reference used in javadoc tags {@code see}, {@code link} and
027 * {@code linkplain}. Similar to {@link JavadocReference} but can distinguish between package names and class names. The
028 * package name is always set for a resolved reference (except for references to modules). The member is always the
029 * normalized form containing only fully qualified type names (without argument names), separated by {@code ,} without
030 * any whitespace characters. Also the member type is always resolved to one of {@link MemberType} (in case the
031 * reference contains a member part).
032 */
033public class FullyQualifiedJavadocReference
034    extends JavadocReference
035{
036
037    /** if false, points to a class/package which is part of the current classloader (and not any of its parents) */
038    private final boolean isExternal;
039
040    private final Optional<String> packageName;
041
042    private final Optional<MemberType> memberType;
043
044    /** The type of the member part of the reference. */
045    public enum MemberType
046    {
047        FIELD, METHOD, CONSTRUCTOR
048    }
049
050    public FullyQualifiedJavadocReference( String packageName, boolean isExternal )
051    {
052        this( packageName, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), isExternal );
053    }
054
055    public FullyQualifiedJavadocReference( String packageName, Optional<String> label, boolean isExternal )
056    {
057        this( packageName, Optional.empty(), Optional.empty(), Optional.empty(), label, isExternal );
058    }
059
060    public FullyQualifiedJavadocReference( String packageName, String className, boolean isExternal )
061    {
062        this( packageName, Optional.of( className ), Optional.empty(), Optional.empty(), Optional.empty(),
063              isExternal );
064    }
065
066    public FullyQualifiedJavadocReference( String packageName, String className, String member, MemberType memberType,
067                                           boolean isExternal )
068    {
069        this( packageName, Optional.of( className ), Optional.of( member ), Optional.of( memberType ),
070              Optional.empty(), isExternal );
071    }
072
073    public FullyQualifiedJavadocReference( String packageName, Optional<String> className, Optional<String> member,
074                                           Optional<MemberType> memberType, Optional<String> label, boolean isExternal )
075    {
076        this( Optional.empty(), Optional.of( packageName ), className, member, memberType, label, isExternal );
077    }
078
079    public FullyQualifiedJavadocReference( Optional<String> moduleName, Optional<String> packageName,
080                                           Optional<String> className, Optional<String> member,
081                                           Optional<MemberType> memberType, Optional<String> label,
082                                           boolean isExternal )
083    {
084        super( moduleName, className, member, label );
085        this.packageName = packageName;
086        this.isExternal = isExternal;
087        if ( !moduleName.isPresent() && !packageName.isPresent() )
088        {
089            throw new IllegalArgumentException( "At least one of module name or package name needs to be set" );
090        }
091        if ( member.isPresent() )
092        {
093            if ( !memberType.isPresent() )
094            {
095                throw new IllegalArgumentException( "When member is set, also the member type needs to be set" );
096            }
097            if ( member.get().matches( ".*\\s.*" ) )
098            {
099                throw new IllegalArgumentException( "member must not contain any whitespace characters!" );
100            }
101        }
102        this.memberType = memberType;
103    }
104
105    /**
106     * 
107     * @return {@code true} in case this class/package is part of another classloader
108     */
109    public boolean isExternal()
110    {
111        return isExternal;
112    }
113
114    /** @return the package name of the referenced class */
115    public Optional<String> getPackageName()
116    {
117        return packageName;
118    }
119
120    /**
121     * @return the simple class name of the referenced class, may be prefixed by the declaring class names, separated by
122     *         '.' (for inner classes)
123     */
124    public Optional<String> getClassName()
125    {
126        return getPackageNameClassName();
127    }
128
129    /** @return the type of the member. Only empty if no member is set. */
130    public Optional<MemberType> getMemberType()
131    {
132        return memberType;
133    }
134
135    public Optional<String> getFullyQualifiedClassName()
136    {
137        if ( getClassName().isPresent() && getPackageName().isPresent() )
138        {
139            return Optional.of( getPackageName().get() + "." + getClassName().get() );
140        }
141        else
142        {
143            return Optional.empty();
144        }
145    }
146
147    @Override
148    public String toString()
149    {
150        return "FullyQualifiedJavadocReference [moduleName=" + getModuleName() + ", packageName=" + packageName
151            + ", className=" + getClassName() + ", memberType=" + memberType + ", member=" + getMember() + ", label="
152            + getLabel() + ", isExternal=" + isExternal + "]";
153    }
154
155    @Override
156    public int hashCode()
157    {
158        final int prime = 31;
159        int result = super.hashCode();
160        result = prime * result + Objects.hash( memberType, packageName, isExternal );
161        return result;
162    }
163
164    @Override
165    public boolean equals( Object obj )
166    {
167        if ( this == obj )
168        {
169            return true;
170        }
171        if ( !super.equals( obj ) )
172        {
173            return false;
174        }
175        if ( getClass() != obj.getClass() )
176        {
177            return false;
178        }
179        FullyQualifiedJavadocReference other = (FullyQualifiedJavadocReference) obj;
180        return Objects.equals( memberType, other.memberType ) && Objects.equals( packageName, other.packageName )
181                        && isExternal == other.isExternal;
182    }
183
184}