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