001/* 002 * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package org.jdrupes.mdoclet.internal.doclets.toolkit.util; 027 028/** 029 * Abstraction for simple relative URIs, consisting of a path and an 030 * optional fragment. DocLink objects can be created by the constructors 031 * below or from a DocPath using the convenience 032 * {@link DocPath#fragment fragment} method. 033 */ 034public class DocLink { 035 final DocPath path; 036 final String fragment; 037 038 /** 039 * Creates a DocLink representing the URI {@code #fragment}. 040 * @param fragment the fragment 041 * @return the DocLink 042 */ 043 public static DocLink fragment(String fragment) { 044 return new DocLink((DocPath) null, fragment); 045 } 046 047 /** 048 * Creates a DocLink representing the URI {@code path}. 049 * @param path the path 050 */ 051 public DocLink(DocPath path) { 052 this(path, null); 053 } 054 055 /** 056 * Creates a DocLink representing the URI {@code path#fragment}. 057 * Any of the component parts may be null. 058 * @param path the path 059 * @param fragment the fragment 060 */ 061 public DocLink(DocPath path, String fragment) { 062 this.path = path; 063 this.fragment = fragment; 064 } 065 066 /** 067 * Creates a DocLink representing the URI {@code path#fragment}. 068 * Any of the component parts may be null. 069 * @param path the path 070 * @param fragment the fragment 071 */ 072 public DocLink(String path, String fragment) { 073 this(DocPath.create(path), fragment); 074 } 075 076 /** 077 * Creates a DocLink formed by relativizing the path against a given base. 078 * @param base the base 079 * @return the DocLink 080 */ 081 public DocLink relativizeAgainst(DocPath base) { 082 if (base.isEmpty() || path == null) { 083 return this; 084 } 085 086 // The following guards against the (ugly) use-case of using DocPath to 087 // contain a URL 088 if (isAbsoluteURL(path)) { 089 return this; 090 } 091 092 DocPath newPath = base.relativize(path); 093 // avoid generating an empty link by using the basename of the path if 094 // necessary 095 if (newPath.isEmpty() && isEmpty(fragment)) { 096 newPath = path.basename(); 097 } 098 return new DocLink(newPath, fragment); 099 } 100 101 public DocLink withFragment(String fragment) { 102 return new DocLink(path, fragment); 103 } 104 105 // return true if the path begins <letters>:// 106 private boolean isAbsoluteURL(DocPath path) { 107 String s = path.getPath(); 108 for (int i = 0; i < s.length(); i++) { 109 char c = s.charAt(i); 110 if (Character.isLetter(c)) { 111 continue; 112 } 113 return (c == ':' && i + 2 < s.length() && s.charAt(i + 1) == '/' 114 && s.charAt(i + 2) == '/'); 115 } 116 return false; 117 } 118 119 /** 120 * Returns the link in the form "path#fragment", omitting any empty 121 * components. 122 * @return the string 123 */ 124 @Override 125 public String toString() { 126 // common fast path 127 if (path != null && isEmpty(fragment)) 128 return path.getPath(); 129 130 StringBuilder sb = new StringBuilder(); 131 if (path != null) 132 sb.append(path.getPath()); 133 if (!isEmpty(fragment)) 134 sb.append("#").append(fragment); 135 return sb.toString(); 136 } 137 138 private static boolean isEmpty(String s) { 139 return (s == null) || s.isEmpty(); 140 } 141}