001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUAbstractCollection<String> 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.jsp.util; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsResource; 032import org.opencms.jsp.CmsJspResourceWrapper; 033import org.opencms.main.CmsLog; 034import org.opencms.main.OpenCms; 035import org.opencms.relations.CmsLink; 036import org.opencms.relations.CmsRelationType; 037import org.opencms.util.CmsStringUtil; 038import org.opencms.xml.types.CmsXmlVarLinkValue; 039 040import java.util.AbstractCollection; 041import java.util.Collections; 042import java.util.Iterator; 043import java.util.Map; 044import java.util.Objects; 045import java.util.Optional; 046import java.util.concurrent.ConcurrentHashMap; 047 048import org.apache.commons.logging.Log; 049 050/** 051 * Wrapper for handling links in template/formatter JSP EL. 052 */ 053public class CmsJspLinkWrapper extends AbstractCollection<String> { 054 055 /** Logger instance for this class. */ 056 private static final Log LOG = CmsLog.getLog(CmsJspLinkWrapper.class); 057 058 /** Stored CMS context. */ 059 protected CmsObject m_cms; 060 061 /** The link literal from which this wrapper was created. */ 062 protected String m_link; 063 064 /** Cached internal/external state. */ 065 protected Boolean m_internal; 066 067 /** Cached link target resource. */ 068 protected Optional<CmsResource> m_resource; 069 070 /** Cached links (online, perma, server). */ 071 protected Map<String, String> m_stringCache = new ConcurrentHashMap<>(); 072 073 /** If <code>true</code> then empty links are allowed. */ 074 private boolean m_allowEmpty; 075 076 /** 077 * Creates a new link wrapper.<p> 078 * 079 * The link parameter should be in the same format that you enter in an XML content of field of type OpenCmsVarLink, i.e. 080 * either a full external URL or a site path with a query string attached. 081 * 082 * @param cms the CMS context 083 * @param link the link to wrap 084 */ 085 public CmsJspLinkWrapper(CmsObject cms, String link) { 086 087 this(cms, link, false); 088 } 089 090 /** 091 * Creates a new link wrapper.<p> 092 * 093 * The link parameter should be in the same format that you enter in an XML content of field of type OpenCmsVarLink, i.e. 094 * either a full external URL or a site path with a query string attached. 095 * 096 * @param cms the CMS context 097 * @param link the link to wrap 098 * @param allowEmpty if <code>true</code> then empty links are allowed 099 */ 100 public CmsJspLinkWrapper(CmsObject cms, String link, boolean allowEmpty) { 101 102 m_cms = cms; 103 m_link = link; 104 m_allowEmpty = allowEmpty; 105 } 106 107 /** 108 * @see java.lang.Object#equals(java.lang.Object) 109 */ 110 @Override 111 public boolean equals(Object obj) { 112 113 if (obj == this) { 114 return true; 115 } 116 if (obj instanceof CmsJspLinkWrapper) { 117 return obj.toString().equals(toString()); 118 } 119 return false; 120 } 121 122 /** 123 * Returns <code>true</code> if the link is internal. 124 * 125 * @return <code>true</code> if the link is internal 126 */ 127 public boolean getIsInternal() { 128 129 if (m_internal == null) { 130 if (isEmpty()) { 131 m_internal = Boolean.FALSE; 132 } else { 133 m_internal = Boolean.valueOf( 134 null != CmsXmlVarLinkValue.getInternalPathAndQuery(m_cms, getServerLink())); 135 } 136 } 137 return m_internal.booleanValue(); 138 } 139 140 /** 141 * Performs normal link substitution. 142 * 143 * @return the substituted link 144 */ 145 public String getLink() { 146 147 return m_stringCache.computeIfAbsent( 148 "link", 149 k -> (!isEmpty() ? A_CmsJspValueWrapper.substituteLink(m_cms, m_link) : "")); 150 } 151 152 /** 153 * Gets the literal from which this wrapper was constructed. 154 * 155 * @return the original link literal 156 */ 157 public String getLiteral() { 158 159 return m_link; 160 } 161 162 /** 163 * Performs online link substitution. 164 * 165 * @return the online link 166 */ 167 public String getOnlineLink() { 168 169 return m_stringCache.computeIfAbsent( 170 "online", 171 k -> (!isEmpty() ? OpenCms.getLinkManager().getOnlineLink(m_cms, m_link) : "")); 172 } 173 174 /** 175 * Performs permalink substitution. 176 * 177 * @return the permalink 178 */ 179 public String getPermaLink() { 180 181 return m_stringCache.computeIfAbsent( 182 "perma", 183 k -> (!isEmpty() ? OpenCms.getLinkManager().getPermalink(m_cms, m_link) : "")); 184 } 185 186 /** 187 * Gets the resource wrapper for the link target. 188 * 189 * @return the resource wrapper for the target 190 */ 191 public CmsJspResourceWrapper getResource() { 192 193 if (m_resource == null) { 194 try { 195 String link = CmsXmlVarLinkValue.getInternalPathAndQuery(m_cms, getServerLink()); 196 if (link == null) { 197 m_resource = Optional.empty(); 198 } else { 199 CmsLink linkObj = new CmsLink(/*name=*/null, CmsRelationType.HYPERLINK, link, true); 200 linkObj.checkConsistency(m_cms); 201 m_resource = Optional.ofNullable(linkObj.getResource()); 202 } 203 } catch (Exception e) { 204 LOG.warn(e.getLocalizedMessage(), e); 205 m_resource = Optional.empty(); 206 } 207 } 208 if (m_resource.isPresent()) { 209 return CmsJspResourceWrapper.wrap(m_cms, m_resource.get()); 210 } else { 211 return null; 212 } 213 214 } 215 216 /** 217 * Performs server link substitution. 218 * 219 * @return the server link 220 */ 221 public String getServerLink() { 222 223 return m_stringCache.computeIfAbsent( 224 "server", 225 k -> (!isEmpty() ? OpenCms.getLinkManager().getServerLink(m_cms, m_link) : "")); 226 } 227 228 /** 229 * Returns the wrapped link as a String as in {@link #toString()}.<p> 230 * 231 * @return the wrapped link as a String 232 */ 233 public String getToString() { 234 235 return toString(); 236 } 237 238 /** 239 * @see org.opencms.jsp.util.A_CmsJspValueWrapper#hashCode() 240 */ 241 @Override 242 public int hashCode() { 243 244 if (m_link == null) { 245 return 0; 246 } 247 return toString().hashCode(); 248 } 249 250 /** 251 * Returns <code>true</code> if the wrapped link has been initialized.<p> 252 * 253 * @return <code>true</code> if the wrapped link has been initialized 254 */ 255 @Override 256 public boolean isEmpty() { 257 258 if (m_allowEmpty) { 259 return m_link == null; 260 } 261 return CmsStringUtil.isEmptyOrWhitespaceOnly(m_link); 262 } 263 264 /** 265 * @see java.util.AbstractCollection#iterator() 266 */ 267 @Override 268 public Iterator<String> iterator() { 269 270 return isEmpty() ? Collections.emptyIterator() : Collections.singletonList(toString()).iterator(); 271 } 272 273 /** 274 * @see java.util.AbstractCollection#size() 275 */ 276 @Override 277 public int size() { 278 279 return isEmpty() ? 0 : 1; 280 } 281 282 /** 283 * Returns the wrapped link as a String as in {@link #getLink()}.<p> 284 * 285 * @return the wrapped link as a String 286 * 287 * @see #getLiteral() 288 */ 289 @Override 290 public String toString() { 291 292 return getLink(); 293 } 294}