001/* 002 * Copyright 2010 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.web.editor; 017 018import java.util.HashMap; 019import java.util.Map; 020 021import org.apache.avalon.framework.service.ServiceException; 022import org.apache.avalon.framework.service.ServiceManager; 023import org.apache.cocoon.components.ContextHelper; 024import org.apache.cocoon.environment.Request; 025 026import org.ametys.cms.repository.Content; 027import org.ametys.cms.transformation.URIResolver; 028import org.ametys.core.util.URLEncoder; 029import org.ametys.plugins.repository.UnknownAmetysObjectException; 030import org.ametys.plugins.repository.metadata.RichText; 031import org.ametys.plugins.repository.metadata.UnknownMetadataException; 032import org.ametys.plugins.repository.version.VersionableAmetysObject; 033import org.ametys.web.URIPrefixHandler; 034import org.ametys.web.repository.content.WebContent; 035 036/** 037 * {@link URIResolver} for type "local".resources local to a Content 038 * These links or images point resources local to a Content. 039 */ 040public class LocalURIResolver extends org.ametys.cms.transformation.LocalURIResolver 041{ 042 /** The URI prefix handler */ 043 protected URIPrefixHandler _prefixHandler; 044 045 @Override 046 public void service(ServiceManager manager) throws ServiceException 047 { 048 super.service(manager); 049 _prefixHandler = (URIPrefixHandler) manager.lookup(URIPrefixHandler.ROLE); 050 } 051 052 @Override 053 public String getType() 054 { 055 return "local"; 056 } 057 058 @Override 059 public String resolve(String uri, boolean download, boolean absolute, boolean internal) 060 { 061 // uri are like content://UUID@metadata;data/file.ext 062 int i = uri.indexOf('@'); 063 int j = uri.indexOf(';', i); 064 String id = uri.substring(0, i); 065 String metadata = uri.substring(i + 1, j); 066 String path = uri.substring(j + 1); 067 068 try 069 { 070 Request request = ContextHelper.getRequest(_context); 071 072 String contentVersion = null; 073 // The content should be the one from request (UUID) but in that case, getRevision will be always the head on 074 Content content = (Content) request.getAttribute(Content.class.getName()); 075 if (content == null) 076 { 077 // Some time (such as frontoffice edition) the image is rendered with no content in attrbiute 078 content = _ametysObjectResolver.resolveById(id); 079 } 080 081 String siteName; 082 if (content instanceof WebContent) 083 { 084 siteName = ((WebContent) content).getSiteName(); 085 } 086 else 087 { 088 siteName = (String) request.getAttribute("siteName"); 089 } 090 091 if (siteName == null) 092 { 093 return super.resolve(uri, download, absolute, internal); 094 } 095 096 if (id.equals(content.getId())) 097 { 098 contentVersion = ((VersionableAmetysObject) content).getRevision(); 099 } 100 101 RichText richText = _getMeta(content.getMetadataHolder(), metadata); 102 try 103 { 104 richText.getAdditionalDataFolder().getFile(path); 105 } 106 catch (UnknownAmetysObjectException e) 107 { 108 getLogger().warn("Cannot resolve link " + uri); 109 return ""; 110 } 111 112 Map<String, String> params = new HashMap<>(); 113 114 if (download) 115 { 116 params.put("download", "true"); 117 } 118 119 if (contentVersion != null) 120 { 121 params.put("contentVersion", contentVersion); 122 } 123 124 StringBuilder resultPath = new StringBuilder(); 125 126 if (internal) 127 { 128 resultPath.append("cocoon://").append(siteName); 129 } 130 else if (absolute) 131 { 132 resultPath.append(_prefixHandler.getAbsoluteUriPrefix(siteName)); 133 } 134 else 135 { 136 resultPath.append(_prefixHandler.getUriPrefix(siteName)); 137 } 138 139 resultPath.append("/_contents") 140 .append(content.getPath().replaceAll(":", "%3A")) 141 .append("/_metadata/").append(metadata) 142 .append("/_data/") 143 .append(URLEncoder.encodePath(path)); 144 145 return URLEncoder.encodeURI(resultPath.toString(), params); 146 } 147 catch (Exception e) 148 { 149 throw new IllegalStateException(e); 150 } 151 } 152 153 @Override 154 public String resolveImage(String uri, int height, int width, boolean download, boolean absolute, boolean internal) 155 { 156 if (height == 0 && width == 0) 157 { 158 return resolve(uri, download, absolute, internal); 159 } 160 161 // uri are like content://UUID@metadata;data/file.ext 162 int i = uri.indexOf('@'); 163 int j = uri.indexOf(';', i); 164 String id = uri.substring(0, i); 165 String metadata = uri.substring(i + 1, j); 166 String path = uri.substring(j + 1); 167 168 try 169 { 170 Request request = ContextHelper.getRequest(_context); 171 172 String contentVersion = null; 173 Content content = (Content) request.getAttribute(Content.class.getName()); // FIXME the content should be the one from request (UUID) but in that case, getRevision will be always the head one 174 if (content == null) 175 { 176 throw new IllegalStateException("Cannot resolve a local link to an unknown content for uri " + request.getRequestURI()); 177 } 178 if (id.equals(content.getId())) // FIXME should be the right one directly : we should not take the one from the request 179 { 180 contentVersion = ((VersionableAmetysObject) content).getRevision(); 181 } 182 183 String siteName; 184 if (content instanceof WebContent) 185 { 186 siteName = ((WebContent) content).getSiteName(); 187 } 188 else 189 { 190 siteName = (String) request.getAttribute("siteName"); 191 } 192 193 RichText richText = _getMeta(content.getMetadataHolder(), metadata); 194 try 195 { 196 richText.getAdditionalDataFolder().getFile(path); 197 } 198 catch (UnknownAmetysObjectException e) 199 { 200 getLogger().warn("Cannot resolve link " + uri); 201 return ""; 202 } 203 catch (UnknownMetadataException e) 204 { 205 getLogger().warn("Cannot resolve link " + uri); 206 return ""; 207 } 208 209 StringBuilder resultPath = new StringBuilder(); 210 211 if (internal) 212 { 213 resultPath.append("cocoon://").append(siteName); 214 } 215 else if (absolute) 216 { 217 resultPath.append(_prefixHandler.getAbsoluteUriPrefix(siteName)); 218 } 219 else 220 { 221 resultPath.append(_prefixHandler.getUriPrefix(siteName)); 222 } 223 224 resultPath.append("/_contents-images") 225 .append(content.getPath().replaceAll(":", "%3A")) 226 .append("/_metadata/").append(metadata) 227 .append("/_data/") 228 .append(URLEncoder.encodePath(path)) 229 .append("_").append(height).append("x").append(width); 230 231 Map<String, String> params = new HashMap<>(); 232 if (download) 233 { 234 params.put("download", "true"); 235 } 236 if (contentVersion != null) 237 { 238 params.put("contentVersion", contentVersion); 239 } 240 241 return URLEncoder.encodeURI(resultPath.toString(), params); 242 } 243 catch (Exception e) 244 { 245 throw new IllegalStateException(e); 246 } 247 } 248 249 @Override 250 public String resolveBoundedImage(String uri, int maxHeight, int maxWidth, boolean download, boolean absolute, boolean internal) 251 { 252 if (maxHeight == 0 && maxWidth == 0) 253 { 254 return resolve(uri, download, absolute, internal); 255 } 256 257 // uri are like content://UUID@metadata;data/file.ext 258 int i = uri.indexOf('@'); 259 int j = uri.indexOf(';', i); 260 String id = uri.substring(0, i); 261 String metadata = uri.substring(i + 1, j); 262 String path = uri.substring(j + 1); 263 264 try 265 { 266 Request request = ContextHelper.getRequest(_context); 267 268 String contentVersion = null; 269 Content content = (Content) request.getAttribute(Content.class.getName()); // FIXME the content should be the one from request (UUID) but in that cas, getRevision will be always the head on 270 if (content == null) 271 { 272 throw new IllegalStateException("Cannot resolve a local link to an unknown content for uri " + request.getRequestURI()); 273 } 274 if (id.equals(content.getId())) // FIXME should be the right one directly : we should not take the one from the request 275 { 276 contentVersion = ((VersionableAmetysObject) content).getRevision(); 277 } 278 279 String siteName; 280 if (content instanceof WebContent) 281 { 282 siteName = ((WebContent) content).getSiteName(); 283 } 284 else 285 { 286 siteName = (String) request.getAttribute("siteName"); 287 } 288 289 RichText richText = _getMeta(content.getMetadataHolder(), metadata); 290 try 291 { 292 richText.getAdditionalDataFolder().getFile(path); 293 } 294 catch (UnknownAmetysObjectException e) 295 { 296 getLogger().warn("Cannot resolve link " + uri); 297 return ""; 298 } 299 300 StringBuilder resultPath = new StringBuilder(); 301 302 if (internal) 303 { 304 resultPath.append("cocoon://").append(siteName); 305 } 306 else if (absolute) 307 { 308 resultPath.append(_prefixHandler.getAbsoluteUriPrefix(siteName)); 309 } 310 else 311 { 312 resultPath.append(_prefixHandler.getUriPrefix(siteName)); 313 } 314 315 resultPath.append("/_contents-images") 316 .append(content.getPath().replaceAll(":", "%3A")) 317 .append("/_metadata/").append(metadata) 318 .append("/_data/") 319 .append(URLEncoder.encodePath(path)) 320 .append("_max").append(maxWidth).append("x").append(maxWidth); 321 322 Map<String, String> params = new HashMap<>(); 323 if (download) 324 { 325 params.put("download", "true"); 326 } 327 if (contentVersion != null) 328 { 329 params.put("contentVersion", contentVersion); 330 } 331 332 return URLEncoder.encodeURI(resultPath.toString(), params); 333 } 334 catch (Exception e) 335 { 336 throw new IllegalStateException(e); 337 } 338 } 339}