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.cms.transformation; 017 018import java.io.InputStream; 019import java.util.Collections; 020 021import org.apache.avalon.framework.context.Context; 022import org.apache.avalon.framework.context.ContextException; 023import org.apache.avalon.framework.context.Contextualizable; 024import org.apache.avalon.framework.logger.AbstractLogEnabled; 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.avalon.framework.service.Serviceable; 028import org.apache.commons.lang.StringUtils; 029 030import org.ametys.cms.URIPrefixHandler; 031import org.ametys.cms.transformation.ConsistencyChecker.CHECK; 032import org.ametys.core.util.FilenameUtils; 033import org.ametys.core.util.URIUtils; 034import org.ametys.plugins.explorer.resources.Resource; 035import org.ametys.plugins.repository.AmetysObject; 036import org.ametys.plugins.repository.AmetysObjectResolver; 037import org.ametys.plugins.repository.UnknownAmetysObjectException; 038import org.ametys.plugins.repository.version.VersionableAmetysObject; 039import org.ametys.runtime.i18n.I18nizableText; 040 041/** 042 * {@link URIResolver} for type "explorer". <br> 043 * These links point to a file from the resources explorer. 044 */ 045public class ResourceURIResolver extends AbstractLogEnabled implements URIResolver, Serviceable, Contextualizable 046{ 047 /** The ametys object resolver. */ 048 protected AmetysObjectResolver _resolver; 049 /** The avalon context. */ 050 protected Context _context; 051 /** The URI prefix handler */ 052 protected URIPrefixHandler _prefixHandler; 053 054 @Override 055 public void contextualize(Context context) throws ContextException 056 { 057 _context = context; 058 } 059 060 @Override 061 public void service(ServiceManager manager) throws ServiceException 062 { 063 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 064 _prefixHandler = (URIPrefixHandler) manager.lookup(URIPrefixHandler.ROLE); 065 } 066 067 @Override 068 public String getType() 069 { 070 return "explorer"; 071 } 072 073 @Override 074 public String resolve(String uri, boolean download, boolean absolute, boolean internal) 075 { 076 return _resolve(uri, download, absolute, internal, "resources", null); 077 } 078 079 @Override 080 public String resolveImage(String uri, int height, int width, boolean download, boolean absolute, boolean internal) 081 { 082 if (height == 0 && width == 0) 083 { 084 return resolve(uri, download, absolute, internal); 085 } 086 087 088 return _resolve(uri, download, absolute, internal, "resources-images", "_" + height + "x" + width); 089 } 090 091 @Override 092 public String resolveImageAsBase64(String uri, int height, int width) 093 { 094 return resolveImageAsBase64(uri, height, width, 0, 0, 0, 0); 095 } 096 097 @Override 098 public String resolveBoundedImage(String uri, int maxHeight, int maxWidth, boolean download, boolean absolute, boolean internal) 099 { 100 if (maxHeight == 0 && maxWidth == 0) 101 { 102 return resolve(uri, download, absolute, internal); 103 } 104 105 return _resolve(uri, download, absolute, internal, "resources-images", "_max" + maxHeight + "x" + maxWidth); 106 } 107 108 @Override 109 public String resolveBoundedImageAsBase64(String uri, int maxHeight, int maxWidth) 110 { 111 return resolveImageAsBase64(uri, 0, 0, maxHeight, maxWidth, 0, 0); 112 } 113 114 @Override 115 public String resolveCroppedImage(String uri, int cropHeight, int cropWidth, boolean download, boolean absolute, boolean internal) 116 { 117 if (cropHeight == 0 && cropWidth == 0) 118 { 119 return resolve(uri, download, absolute, internal); 120 } 121 122 return _resolve(uri, download, absolute, internal, "resources-images", "_crop" + cropHeight + "x" + cropWidth); 123 } 124 125 @Override 126 public String resolveCroppedImageAsBase64(String uri, int cropHeight, int cropWidth) 127 { 128 return resolveImageAsBase64(uri, 0, 0, 0, 0, cropHeight, cropWidth); 129 } 130 131 /** 132 * Get the URI prefix 133 * @param object The object 134 * @param download true if the pointed resource is to be downloaded. 135 * @param absolute true if the url must be absolute 136 * @param internal true to get an internal URI. 137 * @return the URI prefix 138 */ 139 protected String getUriPrefix (AmetysObject object, boolean download, boolean internal, boolean absolute) 140 { 141 if (internal) 142 { 143 return "cocoon://"; 144 } 145 else if (absolute) 146 { 147 return _prefixHandler.getAbsoluteUriPrefix(); 148 } 149 else 150 { 151 return _prefixHandler.getUriPrefix(); 152 } 153 } 154 155 /** 156 * Creates a full uri 157 * @param uri the base uri, ie the resource id 158 * @param download true to create a forced download uri 159 * @param absolute true to create an absolute uri (if internal is false) 160 * @param internal true to create an internal uri 161 * @param prefix Prefix on the uri 162 * @param suffix Suffix on the uri 163 * @return The created uri 164 */ 165 protected String _resolve(String uri, boolean download, boolean absolute, boolean internal, String prefix, String suffix) 166 { 167 String version = null; 168 String path; 169 Resource resource = null; 170 try 171 { 172 String resourceId = uri; 173 int i = uri.indexOf(";"); 174 if (i != -1) 175 { 176 resourceId = uri.substring(0, i); 177 version = uri.substring(i + 1); 178 } 179 180 resource = (Resource) _resolver.resolveById(resourceId); 181 path = getResourcePath(resource); 182 } 183 catch (UnknownAmetysObjectException e) 184 { 185 getLogger().warn("Link to unexisting resource " + uri); 186 return ""; 187 } 188 189 int i = path.lastIndexOf("."); 190 String extension = i != -1 ? path.substring(i) : null; 191 path = i != -1 ? path.substring(0, i) : path; 192 193 StringBuilder result = new StringBuilder(); 194 195 result.append(getUriPrefix(resource, download, absolute, internal)); 196 197 String realPrefix = getRealPrefix(resource, prefix); 198 if (StringUtils.isNotEmpty(realPrefix)) 199 { 200 result.append("/_").append(realPrefix); 201 } 202 203 if (StringUtils.isNotEmpty(version) && resource instanceof VersionableAmetysObject) 204 { 205 result.append("/__version").append(version); 206 } 207 208 result.append(FilenameUtils.encodePath(path)); 209 210 if (suffix != null) 211 { 212 result.append(suffix); 213 } 214 215 if (extension != null) 216 { 217 result.append(extension); 218 } 219 220 return URIUtils.encodeURI(result.toString(), download ? Collections.singletonMap("download", "true") : null); 221 } 222 223 /** 224 * Get the resource path 225 * @param resource the resource 226 * @return the path 227 */ 228 protected String getResourcePath (Resource resource) 229 { 230 return resource.getResourcePath(); 231 } 232 233 /** 234 * Get the real prefix 235 * @param resource the resource 236 * @param prefix the initial prefix 237 * @return the real prefix 238 */ 239 protected String getRealPrefix (Resource resource, String prefix) 240 { 241 return prefix; 242 } 243 244 /** 245 * Get an image's bytes encoded as base64, optionally resized. 246 * @param uri the image URI. 247 * @param height the specified height. Ignored if negative. 248 * @param width the specified width. Ignored if negative. 249 * @param maxHeight the maximum image height. Ignored if height or width is specified. 250 * @param maxWidth the maximum image width. Ignored if height or width is specified. 251 * @param cropHeight The cropping height. Ignored if negative. 252 * @param cropWidth The cropping width. Ignored if negative. 253 * @return the image bytes encoded as base64. 254 */ 255 protected String resolveImageAsBase64(String uri, int height, int width, int maxHeight, int maxWidth, int cropHeight, int cropWidth) 256 { 257 try 258 { 259 Resource resource = (Resource) _resolver.resolveById(uri); 260 try (InputStream dataIs = resource.getInputStream()) 261 { 262 return ImageResolverHelper.resolveImageAsBase64(dataIs, resource.getMimeType(), height, width, maxHeight, maxWidth); 263 } 264 } 265 catch (UnknownAmetysObjectException e) 266 { 267 getLogger().warn("Link to unexisting resource " + uri); 268 return ""; 269 } 270 catch (Exception e) 271 { 272 throw new IllegalStateException(e); 273 } 274 } 275 276 @Override 277 public CHECK checkLink(String uri, boolean shortTest) 278 { 279 try 280 { 281 _resolver.resolveById(uri); 282 return CHECK.SUCCESS; 283 } 284 catch (UnknownAmetysObjectException e) 285 { 286 return CHECK.NOT_FOUND; 287 } 288 } 289 290 @Override 291 public I18nizableText getLabel(String uri) 292 { 293 try 294 { 295 Resource resource = (Resource) _resolver.resolveById(uri); 296 return new I18nizableText("plugin.cms", "PLUGINS_CMS_LINK_RESOURCE_LABEL", Collections.singletonList(resource.getResourcePath())); 297 } 298 catch (UnknownAmetysObjectException e) 299 { 300 return new I18nizableText("plugin.cms", "PLUGINS_CMS_LINK_RESOURCE_UNKNOWN"); 301 } 302 } 303}