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.net.URI; 041import java.net.URISyntaxException; 042import java.util.AbstractCollection; 043import java.util.Collections; 044import java.util.Iterator; 045import java.util.Map; 046import java.util.Optional; 047import java.util.concurrent.ConcurrentHashMap; 048 049import org.apache.commons.logging.Log; 050 051/** 052 * Wrapper for handling links in template/formatter JSP EL. 053 */ 054public class CmsJspLinkWrapper extends AbstractCollection<String> { 055 056 /** Logger instance for this class. */ 057 private static final Log LOG = CmsLog.getLog(CmsJspLinkWrapper.class); 058 059 /** Stored CMS context. */ 060 protected CmsObject m_cms; 061 062 /** The link literal from which this wrapper was created. */ 063 protected String m_link; 064 065 /** Cached internal/external state. */ 066 protected Boolean m_internal; 067 068 /** Cached link target resource. */ 069 protected Optional<CmsResource> m_resource; 070 071 /** Cached links (online, perma, server). */ 072 protected Map<String, String> m_stringCache = new ConcurrentHashMap<>(); 073 074 /** If <code>true</code> then empty links are allowed. */ 075 private boolean m_allowEmpty; 076 077 /** 078 * Creates a new link wrapper.<p> 079 * 080 * The link parameter should be in the same format that you enter in an XML content of field of type OpenCmsVarLink, i.e. 081 * either a full external URL or a site path with a query string attached. 082 * 083 * @param cms the CMS context 084 * @param link the link to wrap 085 */ 086 public CmsJspLinkWrapper(CmsObject cms, String link) { 087 088 this(cms, link, false); 089 } 090 091 /** 092 * Creates a new link wrapper.<p> 093 * 094 * The link parameter should be in the same format that you enter in an XML content of field of type OpenCmsVarLink, i.e. 095 * either a full external URL or a site path with a query string attached. 096 * 097 * @param cms the CMS context 098 * @param link the link to wrap 099 * @param allowEmpty if <code>true</code> then empty links are allowed 100 */ 101 public CmsJspLinkWrapper(CmsObject cms, String link, boolean allowEmpty) { 102 103 m_cms = cms; 104 m_link = link; 105 m_allowEmpty = allowEmpty; 106 } 107 108 /** 109 * @see java.lang.Object#equals(java.lang.Object) 110 */ 111 @Override 112 public boolean equals(Object obj) { 113 114 if (obj == this) { 115 return true; 116 } 117 if (obj instanceof CmsJspLinkWrapper) { 118 return obj.toString().equals(toString()); 119 } 120 return false; 121 } 122 123 /** 124 * Returns <code>true</code> if the link is internal. 125 * 126 * @return <code>true</code> if the link is internal 127 */ 128 public boolean getIsInternal() { 129 130 if (m_internal == null) { 131 if (isEmpty()) { 132 m_internal = Boolean.FALSE; 133 } else { 134 m_internal = Boolean.valueOf( 135 null != CmsXmlVarLinkValue.getInternalPathAndQuery(m_cms, getServerLink())); 136 } 137 } 138 return m_internal.booleanValue(); 139 } 140 141 /** 142 * Performs normal link substitution. 143 * 144 * @return the substituted link 145 */ 146 public String getLink() { 147 148 return m_stringCache.computeIfAbsent( 149 "link", 150 k -> (!isEmpty() ? A_CmsJspValueWrapper.substituteLink(m_cms, m_link) : "")); 151 } 152 153 /** 154 * Gets the literal from which this wrapper was constructed. 155 * 156 * @return the original link literal 157 */ 158 public String getLiteral() { 159 160 return m_link; 161 } 162 163 /** 164 * Performs online link substitution. 165 * 166 * @return the online link 167 */ 168 public String getOnlineLink() { 169 170 return m_stringCache.computeIfAbsent( 171 "online", 172 k -> (!isEmpty() ? OpenCms.getLinkManager().getOnlineLink(m_cms, m_link) : "")); 173 } 174 175 /** 176 * Performs permalink substitution. 177 * 178 * @return the permalink 179 */ 180 public String getPermaLink() { 181 182 return m_stringCache.computeIfAbsent( 183 "perma", 184 k -> (!isEmpty() ? OpenCms.getLinkManager().getPermalink(m_cms, m_link) : "")); 185 } 186 187 /** 188 * Gets the resource wrapper for the link target. 189 * 190 * @return the resource wrapper for the target 191 */ 192 public CmsJspResourceWrapper getResource() { 193 194 if (m_resource == null) { 195 try { 196 String link = CmsXmlVarLinkValue.getInternalPathAndQuery(m_cms, getServerLink()); 197 if (link == null) { 198 m_resource = Optional.empty(); 199 } else { 200 CmsLink linkObj = new CmsLink(/*name=*/null, CmsRelationType.HYPERLINK, link, true); 201 linkObj.checkConsistency(m_cms); 202 m_resource = Optional.ofNullable(linkObj.getResource()); 203 } 204 } catch (Exception e) { 205 LOG.warn(e.getLocalizedMessage(), e); 206 m_resource = Optional.empty(); 207 } 208 } 209 if (m_resource.isPresent()) { 210 return CmsJspResourceWrapper.wrap(m_cms, m_resource.get()); 211 } else { 212 return null; 213 } 214 215 } 216 217 /** 218 * Performs server link substitution. 219 * 220 * @return the server link 221 */ 222 public String getServerLink() { 223 224 return m_stringCache.computeIfAbsent( 225 "server", 226 k -> (!isEmpty() ? OpenCms.getLinkManager().getServerLink(m_cms, m_link) : "")); 227 } 228 229 /** 230 * Returns the wrapped link as a String as in {@link #toString()}.<p> 231 * 232 * @return the wrapped link as a String 233 */ 234 public String getToString() { 235 236 return toString(); 237 } 238 239 /** 240 * Converts the wrapped string to an URI object and returns it. 241 * 242 * <p>If the wrapped string cannont be converted, returns null. 243 * 244 * @return the URI object for the wrapped string, or null if conversion fails 245 */ 246 public URI getToURI() { 247 return toURI(); 248 } 249 250 /** 251 * @see org.opencms.jsp.util.A_CmsJspValueWrapper#hashCode() 252 */ 253 @Override 254 public int hashCode() { 255 256 if (m_link == null) { 257 return 0; 258 } 259 return toString().hashCode(); 260 } 261 262 /** 263 * Returns <code>true</code> if the wrapped link has been initialized.<p> 264 * 265 * @return <code>true</code> if the wrapped link has been initialized 266 */ 267 @Override 268 public boolean isEmpty() { 269 270 if (m_allowEmpty) { 271 return m_link == null; 272 } 273 return CmsStringUtil.isEmptyOrWhitespaceOnly(m_link); 274 } 275 276 /** 277 * @see java.util.AbstractCollection#iterator() 278 */ 279 @Override 280 public Iterator<String> iterator() { 281 282 return isEmpty() ? Collections.emptyIterator() : Collections.singletonList(toString()).iterator(); 283 } 284 285 /** 286 * @see java.util.AbstractCollection#size() 287 */ 288 @Override 289 public int size() { 290 291 return isEmpty() ? 0 : 1; 292 } 293 294 /** 295 * Returns the wrapped link as a String as in {@link #getLink()}.<p> 296 * 297 * @return the wrapped link as a String 298 * 299 * @see #getLiteral() 300 */ 301 @Override 302 public String toString() { 303 304 return getLink(); 305 } 306 307 /** 308 * Converts the wrapped string to an URI object and returns it. 309 * 310 * <p>If the wrapped string cannont be converted, returns null. 311 * 312 * @return the URI object for the wrapped string, or null if conversion fails 313 */ 314 public URI toURI() { 315 316 if (m_link == null) { 317 return null; 318 } 319 try { 320 return new URI(m_link); 321 } catch (URISyntaxException e) { 322 return null; 323 } 324 } 325}