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.xslt; 017 018import java.util.Optional; 019 020import org.apache.avalon.framework.activity.Initializable; 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.cocoon.components.ContextHelper; 029import org.apache.cocoon.environment.Request; 030import org.apache.commons.lang3.StringUtils; 031 032import org.ametys.cms.transformation.URIResolver; 033import org.ametys.cms.transformation.URIResolverExtensionPoint; 034 035/** 036 * This component resolve links and give a static hack access for xslt calls 037 */ 038public class ResolveURIComponent extends AbstractLogEnabled implements Serviceable, Initializable, Contextualizable 039{ 040 private static ResolveURIComponent _instance; 041 042 private static Context _context; 043 044 private URIResolverExtensionPoint _linkResolverExtensionPoint; 045 046 @Override 047 public void contextualize(Context context) throws ContextException 048 { 049 _context = context; 050 } 051 052 @Override 053 public void service(ServiceManager manager) throws ServiceException 054 { 055 _linkResolverExtensionPoint = (URIResolverExtensionPoint) manager.lookup(URIResolverExtensionPoint.ROLE); 056 } 057 058 @Override 059 public void initialize() throws Exception 060 { 061 _instance = this; 062 } 063 064 /** 065 * Resolve an uri upon the LinkResolverExtensionPoint 066 * @param type Type name (defined by the extension to use) 067 * @param uri URI depending on the type 068 * @return The uri resolved, or the uri if there is no resolver adapted 069 */ 070 public static String resolve(String type, String uri) 071 { 072 return resolve(type, uri, false); 073 } 074 075 /** 076 * Resolve an uri upon the LinkResolverExtensionPoint 077 * @param type Type name (defined by the extension to use) 078 * @param uri URI depending on the type 079 * @param download Is this uri for download purposes. 080 * @return The uri resolved, or the uri if there is no resolver adapted 081 */ 082 public static String resolve(String type, String uri, boolean download) 083 { 084 // FIXME CMS-2611 Force absolute 085 Request request = ContextHelper.getRequest(_context); 086 boolean absolute = request.getAttribute("forceAbsoluteUrl") != null ? (Boolean) request.getAttribute("forceAbsoluteUrl") : false; 087 088 return resolve(type, uri, download, absolute); 089 } 090 091 /** 092 * Resolve an uri upon the LinkResolverExtensionPoint 093 * @param type Type name (defined by the extension to use) 094 * @param uri URI depending on the type 095 * @param download Is this uri for download purposes. 096 * @param absolute true to generate absolute url 097 * @return The uri resolved, the empty string if the uri could not be resolved, or the uri itself if there is no resolver adapted 098 */ 099 public static String resolve(String type, String uri, boolean download, boolean absolute) 100 { 101 return resolve(type, uri, download, absolute, false); 102 } 103 104 /** 105 * Resolve an uri upon the LinkResolverExtensionPoint 106 * @param type Type name (defined by the extension to use) 107 * @param uri URI depending on the type 108 * @param download Is this uri for download purposes. 109 * @param absolute true to generate absolute url 110 * @param internal true to get an internal URI. 111 * @return The uri resolved, the empty string if the uri could not be resolved, or the uri itself if there is no resolver adapted 112 */ 113 public static String resolve(String type, String uri, boolean download, boolean absolute, boolean internal) 114 { 115 Request request = ContextHelper.getRequest(_context); 116 Object forceRemoteUrl = request.getAttribute("forceRemoteUrl"); 117 118 boolean remote = forceRemoteUrl != null 119 && (forceRemoteUrl instanceof Boolean && (Boolean) forceRemoteUrl 120 || Boolean.valueOf((String) forceRemoteUrl)); 121 122 String proxiedUri = remote ? type + ";" + uri : uri; 123 URIResolver uriResolver = _instance._linkResolverExtensionPoint.getResolverForType(remote ? "remote" : type); 124 if (uriResolver != null) 125 { 126 try 127 { 128 request.removeAttribute("forceRemoteUrl"); 129 return uriResolver.resolve(proxiedUri, download, absolute, internal); 130 } 131 catch (Exception e) 132 { 133 _instance.getLogger().warn("Error resolving the uri '" + uri + "' with type " + type, e); 134 return ""; 135 } 136 finally 137 { 138 request.setAttribute("forceRemoteUrl", forceRemoteUrl); 139 } 140 } 141 else 142 { 143 return uri; 144 } 145 } 146 147 /** 148 * Resolve an uri upon the LinkResolverExtensionPoint 149 * @param type Type name (defined by the extension to use) 150 * @param uri URI depending on the type 151 * @param height the height 152 * @param width the width 153 * @return The uri resolved, or the uri if there is no resolver adapted 154 */ 155 public static String resolveImage(String type, String uri, int height, int width) 156 { 157 return resolveImage (type, uri, height, width, false); 158 } 159 160 /** 161 * Resolve an uri upon the LinkResolverExtensionPoint 162 * @param type Type name (defined by the extension to use) 163 * @param uri URI depending on the type 164 * @param height the height 165 * @param width the width 166 * @param download Is this uri for download purposes. 167 * @return The uri resolved, or the uri if there is no resolver adapted 168 */ 169 public static String resolveImage(String type, String uri, int height, int width, boolean download) 170 { 171 // FIXME CMS-2611 Force absolute 172 Request request = ContextHelper.getRequest(_context); 173 boolean absolute = request.getAttribute("forceAbsoluteUrl") != null ? (Boolean) request.getAttribute("forceAbsoluteUrl") : false; 174 175 return resolveImage(type, uri, height, width, download, absolute); 176 } 177 178 /** 179 * Resolve an uri upon the LinkResolverExtensionPoint 180 * @param type Type name (defined by the extension to use) 181 * @param uri URI depending on the type 182 * @param height the height 183 * @param width the width 184 * @param download Is this uri for download purposes. 185 * @param absolute true to generate absolute url 186 * @return The uri resolved, the empty string if the uri could not be resolved, or the uri itself if there is no resolver adapted 187 */ 188 public static String resolveImage(String type, String uri, int height, int width, boolean download, boolean absolute) 189 { 190 return resolveImage(type, uri, height, width, download, absolute, false); 191 } 192 193 /** 194 * Resolve an uri upon the LinkResolverExtensionPoint 195 * @param type Type name (defined by the extension to use) 196 * @param uri URI depending on the type 197 * @param height the height 198 * @param width the width 199 * @param download Is this uri for download purposes. 200 * @param absolute true to generate absolute url 201 * @param internal true to get an internal URI. 202 * @return The uri resolved, the empty string if the uri could not be resolved, or the uri itself if there is no resolver adapted 203 */ 204 public static String resolveImage(String type, String uri, int height, int width, boolean download, boolean absolute, boolean internal) 205 { 206 // FIXME CMS-4059 Force base64 encoding. 207 Request request = ContextHelper.getRequest(_context); 208 boolean encodeBase64 = request.getAttribute("forceBase64Encoding") != null ? (Boolean) request.getAttribute("forceBase64Encoding") : false; 209 210 Object forceRemoteUrl = request.getAttribute("forceRemoteUrl"); 211 boolean remote = forceRemoteUrl != null 212 && (forceRemoteUrl instanceof Boolean && (Boolean) forceRemoteUrl 213 || Boolean.valueOf((String) forceRemoteUrl)); 214 215 String proxiedUri = remote ? type + ";" + uri : uri; 216 URIResolver uriResolver = _instance._linkResolverExtensionPoint.getResolverForType(remote ? "remote" : type); 217 if (uriResolver != null) 218 { 219 try 220 { 221 request.removeAttribute("forceRemoteUrl"); 222 if (encodeBase64) 223 { 224 return uriResolver.resolveImageAsBase64(proxiedUri, height, width); 225 } 226 else 227 { 228 return uriResolver.resolveImage(proxiedUri, height, width, download, absolute, internal); 229 } 230 } 231 catch (Exception e) 232 { 233 _instance.getLogger().warn("Error resolving the image of uri '" + uri + "' with type " + type, e); 234 return ""; 235 } 236 finally 237 { 238 request.setAttribute("forceRemoteUrl", forceRemoteUrl); 239 } 240 } 241 else 242 { 243 return uri; 244 } 245 } 246 247 /** 248 * Resolve an uri upon the LinkResolverExtensionPoint return it as a base64-encoded string. 249 * @param type Type name (defined by the extension to use) 250 * @param uri URI depending on the type 251 * @param height the height 252 * @param width the width 253 * @return a base64-encoded string representing the image or empty string if the uri could not be resolved, or the uri itself if there is no resolver adapted 254 */ 255 public static String resolveImageAsBase64(String type, String uri, int height, int width) 256 { 257 URIResolver uriResolver = _instance._linkResolverExtensionPoint.getResolverForType(type); 258 if (uriResolver != null) 259 { 260 try 261 { 262 return uriResolver.resolveImageAsBase64(uri, height, width); 263 } 264 catch (Exception e) 265 { 266 _instance.getLogger().warn("Error resolving the image as base64 of uri '" + uri + "' with type " + type, e); 267 return ""; 268 } 269 } 270 else 271 { 272 return uri; 273 } 274 } 275 276 /** 277 * Resolve an uri upon the LinkResolverExtensionPoint 278 * @param type Type name (defined by the extension to use) 279 * @param uri URI depending on the type 280 * @param maxHeight the max height 281 * @param maxWidth the max width 282 * @return The uri resolved, or the uri if there is no resolver adapted 283 */ 284 public static String resolveBoundedImage(String type, String uri, int maxHeight, int maxWidth) 285 { 286 return resolveBoundedImage (type, uri, maxHeight, maxWidth, false); 287 } 288 289 /** 290 * Resolve an uri upon the LinkResolverExtensionPoint 291 * @param type Type name (defined by the extension to use) 292 * @param uri URI depending on the type 293 * @param maxHeight the max height 294 * @param maxWidth the max width 295 * @param download Is this uri for download purposes. 296 * @return The uri resolved, or the uri if there is no resolver adapted 297 */ 298 public static String resolveBoundedImage(String type, String uri, int maxHeight, int maxWidth, boolean download) 299 { 300 // FIXME CMS-2611 Force absolute 301 Request request = ContextHelper.getRequest(_context); 302 boolean absolute = request.getAttribute("forceAbsoluteUrl") != null ? (Boolean) request.getAttribute("forceAbsoluteUrl") : false; 303 304 return resolveBoundedImage(type, uri, maxHeight, maxWidth, download, absolute); 305 } 306 307 /** 308 * Resolve an uri upon the LinkResolverExtensionPoint 309 * @param type Type name (defined by the extension to use) 310 * @param uri URI depending on the type 311 * @param maxHeight the max height 312 * @param maxWidth the max width 313 * @param download Is this uri for download purposes. 314 * @param absolute true to generate absolute url 315 * @return The uri resolved, the empty string if the uri could not be resolved, or the uri itself if there is no resolver adapted 316 */ 317 public static String resolveBoundedImage(String type, String uri, int maxHeight, int maxWidth, boolean download, boolean absolute) 318 { 319 return resolveBoundedImage(type, uri, maxHeight, maxWidth, download, absolute, false); 320 } 321 322 /** 323 * Resolve an uri upon the LinkResolverExtensionPoint 324 * @param type Type name (defined by the extension to use) 325 * @param uri URI depending on the type 326 * @param maxHeight the max height 327 * @param maxWidth the max width 328 * @param download Is this uri for download purposes. 329 * @param absolute true to generate absolute url 330 * @param internal true to get an internal URI. 331 * @return The uri resolved, the empty string if the uri could not be resolved, or the uri itself if there is no resolver adapted 332 */ 333 public static String resolveBoundedImage(String type, String uri, int maxHeight, int maxWidth, boolean download, boolean absolute, boolean internal) 334 { 335 // FIXME CMS-4059 Force base64 encoding. 336 Request request = ContextHelper.getRequest(_context); 337 boolean encodeBase64 = request.getAttribute("forceBase64Encoding") != null ? (Boolean) request.getAttribute("forceBase64Encoding") : false; 338 339 Object forceRemoteUrl = request.getAttribute("forceRemoteUrl"); 340 boolean remote = forceRemoteUrl != null 341 && (forceRemoteUrl instanceof Boolean && (Boolean) forceRemoteUrl 342 || Boolean.valueOf((String) forceRemoteUrl)); 343 344 String proxiedUri = remote ? type + ";" + uri : uri; 345 URIResolver uriResolver = _instance._linkResolverExtensionPoint.getResolverForType(remote ? "remote" : type); 346 if (uriResolver != null) 347 { 348 try 349 { 350 request.removeAttribute("forceRemoteUrl"); 351 if (encodeBase64) 352 { 353 return uriResolver.resolveBoundedImageAsBase64(proxiedUri, maxHeight, maxWidth); 354 } 355 else 356 { 357 return uriResolver.resolveBoundedImage(proxiedUri, maxHeight, maxWidth, download, absolute, internal); 358 } 359 } 360 catch (Exception e) 361 { 362 _instance.getLogger().warn("Error resolving the image of uri '" + uri + "' with type " + type, e); 363 return ""; 364 } 365 finally 366 { 367 request.setAttribute("forceRemoteUrl", forceRemoteUrl); 368 } 369 } 370 else 371 { 372 return uri; 373 } 374 } 375 376 /** 377 * Resolve an uri upon the LinkResolverExtensionPoint return it as a base64-encoded string. 378 * @param type Type name (defined by the extension to use) 379 * @param uri URI depending on the type 380 * @param maxHeight the max height 381 * @param maxWidth the max width 382 * @return a base64-encoded string representing the image or empty string if the uri could not be resolved, or the uri itself if there is no resolver adapted 383 */ 384 public static String resolveBoundedImageAsBase64(String type, String uri, int maxHeight, int maxWidth) 385 { 386 URIResolver uriResolver = _instance._linkResolverExtensionPoint.getResolverForType(type); 387 if (uriResolver != null) 388 { 389 try 390 { 391 return uriResolver.resolveBoundedImageAsBase64(uri, maxHeight, maxWidth); 392 } 393 catch (Exception e) 394 { 395 _instance.getLogger().warn("Error resolving the bounded image as base64 of uri '" + uri + "' with type " + type, e); 396 return ""; 397 } 398 } 399 else 400 { 401 return uri; 402 } 403 } 404 405 /** 406 * Resolve an uri upon the LinkResolverExtensionPoint 407 * @param type Type name (defined by the extension to use) 408 * @param uri URI depending on the type 409 * @param cropHeight the crop height 410 * @param cropWidth the crop width 411 * @return The uri resolved, or the uri if there is no resolver adapted 412 */ 413 public static String resolveCroppedImage(String type, String uri, int cropHeight, int cropWidth) 414 { 415 return resolveCroppedImage (type, uri, cropHeight, cropWidth, false); 416 } 417 418 /** 419 * Resolve an uri upon the LinkResolverExtensionPoint 420 * @param type Type name (defined by the extension to use) 421 * @param uri URI depending on the type 422 * @param cropHeight the crop height 423 * @param cropWidth the crop width 424 * @param download Is this uri for download purposes. 425 * @return The uri resolved, or the uri if there is no resolver adapted 426 */ 427 public static String resolveCroppedImage(String type, String uri, int cropHeight, int cropWidth, boolean download) 428 { 429 // FIXME CMS-2611 Force absolute 430 Request request = ContextHelper.getRequest(_context); 431 boolean absolute = request.getAttribute("forceAbsoluteUrl") != null ? (Boolean) request.getAttribute("forceAbsoluteUrl") : false; 432 433 return resolveCroppedImage(type, uri, cropHeight, cropWidth, download, absolute); 434 } 435 436 /** 437 * Resolve an uri upon the LinkResolverExtensionPoint 438 * @param type Type name (defined by the extension to use) 439 * @param uri URI depending on the type 440 * @param cropHeight the crop height 441 * @param cropWidth the crop width 442 * @param download Is this uri for download purposes. 443 * @param absolute true to generate absolute url 444 * @return The uri resolved, the empty string if the uri could not be resolved, or the uri itself if there is no resolver adapted 445 */ 446 public static String resolveCroppedImage(String type, String uri, int cropHeight, int cropWidth, boolean download, boolean absolute) 447 { 448 return resolveCroppedImage(type, uri, cropHeight, cropWidth, download, absolute, false); 449 } 450 451 /** 452 * Resolve an uri upon the LinkResolverExtensionPoint 453 * @param type Type name (defined by the extension to use) 454 * @param uri URI depending on the type 455 * @param cropHeight the crop height 456 * @param cropWidth the crop width 457 * @param download Is this uri for download purposes. 458 * @param absolute true to generate absolute url 459 * @param internal true to get an internal URI. 460 * @return The uri resolved, the empty string if the uri could not be resolved, or the uri itself if there is no resolver adapted 461 */ 462 public static String resolveCroppedImage(String type, String uri, int cropHeight, int cropWidth, boolean download, boolean absolute, boolean internal) 463 { 464 // FIXME CMS-4059 Force base64 encoding. 465 Request request = ContextHelper.getRequest(_context); 466 boolean encodeBase64 = request.getAttribute("forceBase64Encoding") != null ? (Boolean) request.getAttribute("forceBase64Encoding") : false; 467 468 URIResolver uriResolver = _instance._linkResolverExtensionPoint.getResolverForType(type); 469 if (uriResolver != null) 470 { 471 try 472 { 473 if (encodeBase64) 474 { 475 return uriResolver.resolveCroppedImageAsBase64(uri, cropHeight, cropWidth); 476 } 477 else 478 { 479 return uriResolver.resolveCroppedImage(uri, cropHeight, cropWidth, download, absolute, internal); 480 } 481 } 482 catch (Exception e) 483 { 484 _instance.getLogger().warn("Error resolving the image of uri '" + uri + "' with type " + type, e); 485 return ""; 486 } 487 } 488 else 489 { 490 return uri; 491 } 492 } 493 494 /** 495 * Resolve an uri upon the LinkResolverExtensionPoint return it as a base64-encoded string. 496 * @param type Type name (defined by the extension to use) 497 * @param uri URI depending on the type 498 * @param cropHeight the crop height 499 * @param cropWidth the crop width 500 * @return a base64-encoded string representing the image or empty string if the uri could not be resolved, or the uri itself if there is no resolver adapted 501 */ 502 public static String resolveCroppedImageAsBase64(String type, String uri, int cropHeight, int cropWidth) 503 { 504 URIResolver uriResolver = _instance._linkResolverExtensionPoint.getResolverForType(type); 505 if (uriResolver != null) 506 { 507 try 508 { 509 return uriResolver.resolveCroppedImageAsBase64(uri, cropHeight, cropWidth); 510 } 511 catch (Exception e) 512 { 513 _instance.getLogger().warn("Error resolving the cropped image as base64 of uri '" + uri + "' with type " + type, e); 514 return ""; 515 } 516 } 517 else 518 { 519 return uri; 520 } 521 } 522 523 /** 524 * Get the mime type. 525 * @param type Type name (defined by the extension to use) 526 * @param uri URI depending on the type 527 * @return the mime type or application/octet-stream if not found 528 */ 529 public static String getMimeType(String type, String uri) 530 { 531 URIResolver uriResolver = _instance._linkResolverExtensionPoint.getResolverForType(type); 532 return Optional.ofNullable(uriResolver) 533 .map(r -> _getMimeTypeSafe(r, uri)) 534 .filter(StringUtils::isNotEmpty) 535 .orElse("application/octet-stream"); 536 } 537 538 private static String _getMimeTypeSafe(URIResolver uriResolver, String uri) 539 { 540 try 541 { 542 return uriResolver.getMimeType(uri); 543 } 544 catch (Exception e) 545 { 546 _instance.getLogger().warn("Error resolving the image to get the mime type of uri '" + uri + "' with type " + uriResolver.getType(), e); 547 return null; 548 } 549 } 550}