001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (C) Alkacon Software (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, 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.gwt; 029 030import org.opencms.db.CmsAlias; 031import org.opencms.db.CmsAliasManager; 032import org.opencms.db.CmsRewriteAlias; 033import org.opencms.file.CmsObject; 034import org.opencms.file.CmsResource; 035import org.opencms.file.CmsResourceFilter; 036import org.opencms.file.CmsVfsResourceNotFoundException; 037import org.opencms.gwt.shared.alias.CmsAliasBean; 038import org.opencms.main.CmsException; 039import org.opencms.main.CmsLog; 040import org.opencms.main.OpenCms; 041import org.opencms.util.CmsUUID; 042 043import java.io.IOException; 044import java.io.StringWriter; 045import java.util.ArrayList; 046import java.util.HashMap; 047import java.util.HashSet; 048import java.util.List; 049import java.util.Locale; 050import java.util.Map; 051import java.util.Set; 052 053import org.apache.commons.logging.Log; 054 055import au.com.bytecode.opencsv.CSVWriter; 056 057/** 058 * This class contains the real implementations of service methods related to aliases.<p> 059 */ 060public class CmsAliasHelper { 061 062 /** The logger for this class. */ 063 private static final Log LOG = CmsLog.getLog(CmsAliasHelper.class); 064 065 /** The internal CMS object. */ 066 private CmsObject m_cms; 067 068 /** 069 * Returns the comma separated alias data.<p> 070 * 071 * @param cms the OpenCms context 072 * 073 * @return the comma separated alias data 074 * 075 * @throws CmsException if something goes wrong reading the alias data 076 */ 077 public String exportAliasesAsCsv(CmsObject cms) throws CmsException { 078 079 String siteRoot = cms.getRequestContext().getSiteRoot(); 080 List<CmsAlias> aliases = OpenCms.getAliasManager().getAliasesForSite(cms, siteRoot); 081 StringWriter writer = new StringWriter(); 082 CSVWriter csvWriter = new CSVWriter(writer); 083 StringBuffer resultBuffer = writer.getBuffer(); 084 for (CmsAlias alias : aliases) { 085 try { 086 CmsResource resource = cms.readResource(alias.getStructureId()); 087 csvWriter.writeNext( 088 new String[] {alias.getAliasPath(), cms.getSitePath(resource), alias.getMode().toString()}); 089 } catch (CmsException e) { 090 LOG.warn("Could not read alias resource", e); 091 continue; 092 } 093 } 094 095 List<CmsRewriteAlias> rewriteAliases = OpenCms.getAliasManager().getRewriteAliases(cms, siteRoot); 096 for (CmsRewriteAlias rewrite : rewriteAliases) { 097 csvWriter.writeNext( 098 new String[] { 099 rewrite.getPatternString(), 100 rewrite.getReplacementString(), 101 rewrite.getMode().toString(), 102 "rewrite"}); 103 } 104 try { 105 csvWriter.flush(); 106 csvWriter.close(); 107 } catch (IOException e) { 108 // can't happen 109 } 110 return resultBuffer.toString(); 111 } 112 113 /** 114 * Saves aliases.<p> 115 * 116 * @param structureId the structure id 117 * @param aliasBeans the alias beans 118 * @throws CmsException if something goes wrong 119 */ 120 public void saveAliases(CmsUUID structureId, List<CmsAliasBean> aliasBeans) throws CmsException { 121 122 CmsAliasManager aliasManager = OpenCms.getAliasManager(); 123 CmsObject cms = m_cms; 124 List<CmsAlias> aliases = new ArrayList<CmsAlias>(); 125 for (CmsAliasBean aliasBean : aliasBeans) { 126 CmsAlias alias = new CmsAlias( 127 structureId, 128 cms.getRequestContext().getSiteRoot(), 129 aliasBean.getSitePath(), 130 aliasBean.getMode()); 131 aliases.add(alias); 132 } 133 aliasManager.saveAliases(cms, structureId, aliases); 134 } 135 136 /** 137 * Sets the CMS object.<p> 138 * 139 * @param cms the CMS object 140 */ 141 public void setCms(CmsObject cms) { 142 143 m_cms = cms; 144 } 145 146 /** 147 * Checks whether a given string is a valid alias path.<p> 148 * 149 * @param path the path to check 150 * @param locale the locale to use for validation messages 151 * 152 * @return null if the string is a valid alias path, else an error message 153 */ 154 protected String checkValidAliasPath(String path, Locale locale) { 155 156 if (org.opencms.db.CmsAlias.ALIAS_PATTERN.matcher(path).matches()) { 157 return null; 158 } else { 159 return Messages.get().getBundle(locale).key(Messages.ERR_ALIAS_INVALID_PATH_0); 160 } 161 } 162 163 /** 164 * Converts a server-side alias object to an alias bean.<p> 165 * 166 * @param alias the server-side alias object 167 * 168 * @return the client-side alias bean 169 */ 170 protected CmsAliasBean convertAliasToBean(CmsAlias alias) { 171 172 return new CmsAliasBean(alias.getAliasPath(), alias.getMode()); 173 } 174 175 /** 176 * Implementation of the getAliasesForPage method.<p> 177 * 178 * @param uuid the structure id of the page 179 * @return the aliases for the given page 180 * 181 * @throws CmsException if something goes wrong 182 */ 183 protected List<CmsAliasBean> getAliasesForPage(CmsUUID uuid) throws CmsException { 184 185 CmsAliasManager aliasManager = OpenCms.getAliasManager(); 186 List<CmsAlias> aliases = aliasManager.getAliasesForStructureId(m_cms, uuid); 187 List<CmsAliasBean> result = new ArrayList<CmsAliasBean>(); 188 for (CmsAlias alias : aliases) { 189 CmsAliasBean bean = convertAliasToBean(alias); 190 result.add(bean); 191 } 192 return result; 193 } 194 195 /** 196 * The internal method used for validating aliases.<p> 197 * 198 * @param uuid the structure id of the resource whose aliases are being validated 199 * @param aliasPaths a map from (arbitrary) ids to alias paths 200 * 201 * @return a map from the same ids to validation error messages 202 * 203 * @throws CmsException if something goes wrong 204 */ 205 protected Map<String, String> validateAliases(CmsUUID uuid, Map<String, String> aliasPaths) throws CmsException { 206 207 Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms); 208 Set<String> seenPaths = new HashSet<String>(); 209 Set<String> duplicatePaths = new HashSet<String>(); 210 for (String path : aliasPaths.values()) { 211 if (seenPaths.contains(path)) { 212 duplicatePaths.add(path); 213 } 214 seenPaths.add(path); 215 } 216 Map<String, String> errorMessagesByPath = new HashMap<String, String>(); 217 for (String path : duplicatePaths) { 218 errorMessagesByPath.put(path, Messages.get().getBundle(locale).key(Messages.ERR_ALIAS_DUPLICATE_PATH_0)); 219 } 220 seenPaths.removeAll(duplicatePaths); 221 222 for (String path : seenPaths) { 223 String pathError = checkValidAliasPath(path, locale); 224 if (pathError != null) { 225 errorMessagesByPath.put(path, pathError); 226 } else { 227 errorMessagesByPath.put(path, null); 228 if (m_cms.existsResource(path, CmsResourceFilter.ALL)) { 229 errorMessagesByPath.put(path, Messages.get().getBundle(locale).key(Messages.ERR_ALIAS_IS_VFS_0)); 230 } else { 231 List<CmsAlias> aliases = OpenCms.getAliasManager().getAliasesForPath( 232 m_cms, 233 m_cms.getRequestContext().getSiteRoot(), 234 path); 235 for (CmsAlias alias : aliases) { 236 CmsUUID otherStructureId = alias.getStructureId(); 237 if (!otherStructureId.equals(uuid)) { 238 try { 239 CmsResource resource = m_cms.readResource(otherStructureId, CmsResourceFilter.ALL); 240 errorMessagesByPath.put( 241 path, 242 Messages.get().getBundle(locale).key( 243 Messages.ERR_ALIAS_ALREADY_USED_1, 244 resource.getRootPath())); 245 break; 246 } catch (CmsVfsResourceNotFoundException e) { 247 // this may happen if there are outdated entries in the database table 248 errorMessagesByPath.put( 249 path, 250 Messages.get().getBundle(locale).key(Messages.ERR_ALIAS_ALREADY_USED_UNKNOWN_0)); 251 break; 252 } 253 } 254 } 255 } 256 257 } 258 } 259 Map<String, String> errorMessagesById = new HashMap<String, String>(); 260 for (String key : aliasPaths.keySet()) { 261 String path = aliasPaths.get(key); 262 if (errorMessagesByPath.containsKey(path)) { 263 String errorMessage = errorMessagesByPath.get(path); 264 errorMessagesById.put(key, errorMessage); 265 } 266 } 267 return errorMessagesById; 268 } 269}