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 GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, 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.relations.CmsLink; 033import org.opencms.relations.CmsRelationType; 034import org.opencms.staticexport.CmsLinkManager; 035import org.opencms.util.CmsFileUtil; 036import org.opencms.util.CmsMacroResolver; 037import org.opencms.util.CmsStringUtil; 038import org.opencms.util.CmsUUID; 039import org.opencms.util.I_CmsMacroResolver; 040 041import java.util.ArrayList; 042import java.util.Arrays; 043import java.util.Collections; 044import java.util.Iterator; 045import java.util.List; 046 047/** 048 * Resolves link macros for jsp pages.<p> 049 * 050 * The only supported macro is the 'link' macro.<p> 051 * 052 * @since 6.5.4 053 */ 054public class CmsJspLinkMacroResolver implements I_CmsMacroResolver { 055 056 /** Identifier for the link macro separator. */ 057 public static final char KEY_SEPARATOR = ':'; 058 059 /** Identifier for the link macro name. */ 060 public static final String MACRO_LINK = "link:"; 061 062 /** Identifier for the link macro name. */ 063 public static final String MACRO_LINK_STRONG = "link.strong:"; 064 065 /** Identifier for the link macro name. */ 066 public static final String MACRO_LINK_WEAK = "link.weak:"; 067 068 /** Identifier for link commands. */ 069 public static final String[] VALUE_NAME_ARRAY = {MACRO_LINK, MACRO_LINK_WEAK, MACRO_LINK_STRONG}; 070 071 /** The link commands wrapped in a List. */ 072 public static final List<String> VALUE_NAMES = Collections.unmodifiableList(Arrays.asList(VALUE_NAME_ARRAY)); 073 074 /** The cms context. */ 075 private CmsObject m_cms; 076 077 /** 078 * If <code>true</code> the macros get really resolved to valid vfs paths, 079 * otherwise only the path/id in the macros are updated. 080 */ 081 private boolean m_forRfs; 082 083 /** The jsp root path. */ 084 private String m_jspRootPath; 085 086 /** The list of links. */ 087 private List<CmsLink> m_links = new ArrayList<CmsLink>(); 088 089 /** 090 * Default constructor.<p> 091 * 092 * @param cms the cms context 093 * @param jspRootPath the (optional) jsp root path, needed for saving from the editor to resolve relative links 094 * @param forRfs Only if <code>true</code> the macros get really resolved to valid vfs paths 095 */ 096 public CmsJspLinkMacroResolver(CmsObject cms, String jspRootPath, boolean forRfs) { 097 098 m_cms = cms; 099 m_forRfs = forRfs; 100 m_jspRootPath = jspRootPath; 101 } 102 103 /** 104 * Returns the links.<p> 105 * 106 * @return the links 107 */ 108 public List<CmsLink> getLinks() { 109 110 return m_links; 111 } 112 113 /** 114 * @see org.opencms.util.I_CmsMacroResolver#getMacroValue(java.lang.String) 115 */ 116 public String getMacroValue(String macro) { 117 118 String path = null; 119 String id = null; 120 121 // validate macro command 122 Iterator<String> it = VALUE_NAMES.iterator(); 123 while (it.hasNext()) { 124 String cmd = it.next().toString(); 125 if (macro.startsWith(cmd)) { 126 // a macro was found 127 path = macro.substring(cmd.length()); 128 macro = cmd; 129 break; 130 } 131 } 132 if (path == null) { 133 // this is an unknown macro, ignore it 134 return null; 135 } 136 137 // we do have a valid link macro now, parse path and id 138 int pos = path.indexOf(KEY_SEPARATOR); 139 if ((pos > -1) && (path.length() > (pos + 1))) { 140 id = path.substring(pos + 1); 141 } 142 if (pos > -1) { 143 path = path.substring(0, pos); 144 } 145 146 // check the id 147 CmsUUID uuid = null; 148 if (CmsStringUtil.isEmptyOrWhitespaceOnly(id)) { 149 if (path != null) { 150 // try to use the path as an id (in case there is only an id) 151 id = path; 152 } else { 153 id = null; 154 } 155 } 156 if (id != null) { 157 try { 158 uuid = new CmsUUID(id); 159 } catch (Exception e) { 160 // ignore 161 } 162 } 163 164 // rewrite the path 165 if ((path == null) || (path.trim().length() == 0)) { 166 path = null; 167 } else { 168 boolean isAbsolute = (path.charAt(0) == '/'); 169 path = CmsFileUtil.normalizePath(path, '/'); 170 if (!isAbsolute) { 171 path = path.substring(1); 172 } 173 if (isAbsolute && !path.startsWith(m_cms.getRequestContext().getSiteRoot())) { 174 // add the site root if needed 175 path = m_cms.getRequestContext().addSiteRoot(path); 176 } else if (m_jspRootPath != null) { 177 // get the site aware absolute path 178 path = CmsLinkManager.getAbsoluteUri(path, CmsResource.getParentFolder(m_jspRootPath)); 179 } 180 } 181 182 // check the relation type 183 CmsRelationType type = CmsRelationType.JSP_WEAK; 184 if (macro == MACRO_LINK_STRONG) { 185 type = CmsRelationType.JSP_STRONG; 186 } 187 188 // get the link object 189 CmsLink link = new CmsLink("link0", type, uuid, path, true); 190 link.checkConsistency(m_cms); // update id/path 191 m_links.add(link); 192 193 if (m_forRfs) { 194 // return the current correct link path 195 return m_cms.getRequestContext().removeSiteRoot(link.getTarget()); 196 } else { 197 // rewrite the macro with the right absolute path and id 198 StringBuffer newMacro = new StringBuffer(128); 199 newMacro.append(I_CmsMacroResolver.MACRO_DELIMITER); 200 newMacro.append(I_CmsMacroResolver.MACRO_START); 201 newMacro.append(macro); 202 newMacro.append(link.getSitePath(m_cms)); 203 if ((link.getStructureId() != null) && !link.getStructureId().isNullUUID()) { 204 newMacro.append(KEY_SEPARATOR).append(link.getStructureId()); 205 } 206 newMacro.append(I_CmsMacroResolver.MACRO_END); 207 return newMacro.toString(); 208 } 209 } 210 211 /** 212 * @see org.opencms.util.I_CmsMacroResolver#isKeepEmptyMacros() 213 */ 214 public boolean isKeepEmptyMacros() { 215 216 return true; 217 } 218 219 /** 220 * Resolves the JSP link management macros in the given input.<p> 221 * 222 * Calls <code>{@link #resolveMacros(String)}</code> once for each macro in the input. 223 * This means "nested" macros are not supported in this implementation, which is fine since 224 * it can't happen in JSP link management anyway.<p> 225 * 226 * @see org.opencms.util.I_CmsMacroResolver#resolveMacros(java.lang.String) 227 */ 228 public String resolveMacros(String input) { 229 230 // clear the list of links 231 m_links.clear(); 232 233 // parse the input string 234 String result; 235 if (input != null) { 236 // resolve the macros 237 result = CmsMacroResolver.resolveMacros(input, this); 238 } else { 239 // nothing to resolve 240 result = null; 241 } 242 // return the result 243 return result; 244 } 245}