Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.cloudinary.Url Maven / Gradle / Ivy
package com.cloudinary;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
import com.cloudinary.utils.Analytics;
import com.cloudinary.utils.Base64Coder;
import com.cloudinary.utils.ObjectUtils;
import com.cloudinary.utils.StringUtils;
import static com.cloudinary.SignatureAlgorithm.SHA256;
public class Url {
private final Cloudinary cloudinary;
private final Configuration config;
private boolean longUrlSignature;
String publicId = null;
String type = null;
String resourceType = null;
String format = null;
String version = null;
Transformation transformation = null;
boolean signUrl;
private AuthToken authToken;
String source = null;
private String urlSuffix;
private Boolean useRootPath;
Map sourceTransformation = null;
String[] sourceTypes = null;
String fallbackContent = null;
Transformation posterTransformation = null;
String posterSource = null;
Url posterUrl = null;
private static final String CL_BLANK = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
public static final String[] DEFAULT_VIDEO_SOURCE_TYPES = {"webm", "mp4", "ogv"};
private static final Pattern VIDEO_EXTENSION_RE = Pattern.compile("\\.(" + StringUtils.join(DEFAULT_VIDEO_SOURCE_TYPES, "|") + ")$");
public Url(Cloudinary cloudinary) {
this.cloudinary = cloudinary;
this.config = new Configuration(cloudinary.config);
this.longUrlSignature = config.longUrlSignature;
this.authToken = config.authToken;
}
public Url clone() {
Url cloned = cloudinary.url();
cloned.config.update(config.asMap());
cloned.fallbackContent = this.fallbackContent;
cloned.format = this.format;
cloned.posterSource = this.posterSource;
if (this.posterTransformation != null)
cloned.posterTransformation = new Transformation(this.posterTransformation);
if (this.posterUrl != null) cloned.posterUrl = this.posterUrl.clone();
cloned.publicId = this.publicId;
cloned.resourceType = this.resourceType;
cloned.signUrl = this.signUrl;
cloned.source = this.source;
if (this.transformation != null) cloned.transformation = new Transformation(this.transformation);
if (this.sourceTransformation != null) {
cloned.sourceTransformation = new HashMap();
for (Map.Entry keyValuePair : this.sourceTransformation.entrySet()) {
cloned.sourceTransformation.put(keyValuePair.getKey(), keyValuePair.getValue());
}
}
cloned.sourceTypes = this.sourceTypes;
cloned.urlSuffix = this.urlSuffix;
cloned.useRootPath = this.useRootPath;
cloned.longUrlSignature = this.longUrlSignature;
return cloned;
}
private static Pattern identifierPattern = Pattern.compile("^(?:([^/]+)/)??(?:([^/]+)/)??(?:v(\\d+)/)?" + "(?:([^#/]+?)(?:\\.([^.#/]+))?)(?:#([^/]+))?$");
/**
* Parses a cloudinary identifier of the form:
* {@code [/][/][v/][.][#]}
*/
public Url fromIdentifier(String identifier) {
Matcher matcher = identifierPattern.matcher(identifier);
if (!matcher.matches()) {
throw new RuntimeException(String.format("Couldn't parse identifier %s", identifier));
}
String resourceType = matcher.group(1);
if (resourceType != null) {
resourceType(resourceType);
}
String type = matcher.group(2);
if (type != null) {
type(type);
}
String version = matcher.group(3);
if (version != null) {
version(version);
}
String publicId = matcher.group(4);
if (publicId != null) {
publicId(publicId);
}
String format = matcher.group(5);
if (format != null) {
format(format);
}
// Signature (group 6) is not used
return this;
}
public Url type(String type) {
this.type = type;
return this;
}
public Url resourcType(String resourceType) {
return resourceType(resourceType);
}
public Url resourceType(String resourceType) {
this.resourceType = resourceType;
return this;
}
public Url publicId(Object publicId) {
this.publicId = ObjectUtils.asString(publicId);
return this;
}
public Url format(String format) {
this.format = format;
return this;
}
public Url cloudName(String cloudName) {
this.config.cloudName = cloudName;
return this;
}
public Url secureDistribution(String secureDistribution) {
this.config.secureDistribution = secureDistribution;
return this;
}
public Url secureCdnSubdomain(boolean secureCdnSubdomain) {
this.config.secureCdnSubdomain = secureCdnSubdomain;
return this;
}
public Url suffix(String urlSuffix) {
this.urlSuffix = urlSuffix;
return this;
}
public Url useRootPath(boolean useRootPath) {
this.useRootPath = useRootPath;
return this;
}
public Url cname(String cname) {
this.config.cname = cname;
return this;
}
public Url version(Object version) {
this.version = ObjectUtils.asString(version);
return this;
}
public Url transformation(Transformation transformation) {
this.transformation = transformation;
return this;
}
public Url secure(boolean secure) {
this.config.secure = secure;
return this;
}
public Url privateCdn(boolean privateCdn) {
this.config.privateCdn = privateCdn;
return this;
}
public Url cdnSubdomain(boolean cdnSubdomain) {
this.config.cdnSubdomain = cdnSubdomain;
return this;
}
public Url shorten(boolean shorten) {
this.config.shorten = shorten;
return this;
}
public Transformation transformation() {
if (this.transformation == null)
this.transformation = new Transformation();
return this.transformation;
}
public Url signed(boolean signUrl) {
this.signUrl = signUrl;
return this;
}
/**
* Set the authorization token. If authToken
has already been set the parameter is merged with the current value unless the parameter value is null
or NULL_AUTH_TOKEN
.
* For example, to generate an authorized URL with a different duration:
*
* {@code
* cloudinary.config.authToken = new AuthToken(KEY).duration(500);
* // later...
* cloudinary.url().signed(true).authToken(new AuthToken().duration(300))
* .type("authenticated").version("1486020273").generate("sample.jpg");
* }
*
*
* @param authToken an authorization token object
* @return this
*/
public Url authToken(AuthToken authToken) {
if (this.authToken == null) {
this.authToken = authToken;
} else if (authToken == null || authToken.equals(AuthToken.NULL_AUTH_TOKEN)) {
this.authToken = authToken;
} else {
this.authToken = this.authToken.merge(authToken);
}
return this;
}
public Url longUrlSignature(boolean isLong) {
this.longUrlSignature = isLong;
return this;
}
public Url sourceTransformation(Map sourceTransformation) {
this.sourceTransformation = sourceTransformation;
return this;
}
public Url sourceTransformationFor(String source, Transformation transformation) {
if (this.sourceTransformation == null) {
this.sourceTransformation = new HashMap();
}
this.sourceTransformation.put(source, transformation);
return this;
}
public Url sourceTypes(String[] sourceTypes) {
this.sourceTypes = sourceTypes;
return this;
}
public Url fallbackContent(String fallbackContent) {
this.fallbackContent = fallbackContent;
return this;
}
public Url posterTransformation(Transformation posterTransformation) {
this.posterTransformation = posterTransformation;
return this;
}
@SuppressWarnings("rawtypes")
public Url posterTransformation(List posterTransformations) {
this.posterTransformation = new Transformation(posterTransformations);
return this;
}
@SuppressWarnings({"rawtypes", "unchecked"})
public Url posterTransformation(Map posterTransformations) {
List transformations = new ArrayList();
Map copy = new HashMap();
copy.putAll(posterTransformations);
transformations.add(copy);
this.posterTransformation = new Transformation(transformations);
return this;
}
public Url posterSource(String posterSource) {
this.posterSource = posterSource;
return this;
}
public Url posterUrl(Url posterUrl) {
this.posterUrl = posterUrl;
return this;
}
public Url poster(Object poster) {
if (poster instanceof Transformation) {
return posterTransformation((Transformation) poster);
} else if (poster instanceof List) {
return posterTransformation((List) poster);
} else if (poster instanceof Map) {
return posterTransformation((Map) poster);
} else if (poster instanceof Url) {
return posterUrl((Url) poster);
} else if (poster instanceof String) {
return posterSource((String) poster);
} else if (poster == null || poster.equals(Boolean.FALSE)) {
return posterSource("");
} else {
throw new IllegalArgumentException("Illegal value type supplied to poster. must be one of: , >, , , ");
}
}
/**
* Indicates whether to add '/v1/' to the URL when the public ID includes folders and a 'version' value was
* not defined.
* When no version is explicitly specified and the public id contains folders, a default v1 version
* is added to the url. This boolean can disable that behaviour.
* @param forceVersion Whether to add the version to the url.
* @return This same Url instance for chaining.
*/
public Url forceVersion(boolean forceVersion){
this.config.forceVersion = forceVersion;
return this;
}
public String generate() {
return generate(null);
}
public String generate(String source) {
boolean useRootPath = this.config.useRootPath;
if (this.useRootPath != null) {
useRootPath = this.useRootPath;
}
if (StringUtils.isEmpty(this.config.cloudName)) {
throw new IllegalArgumentException("Must supply cloud_name in tag or in configuration");
}
if (source == null) {
if (publicId == null) {
if (this.source == null) {
return null;
}
source = this.source;
} else {
source = publicId;
}
}
boolean httpSource = StringUtils.isHttpUrl(source);
if (httpSource) {
if (StringUtils.isEmpty(type) || "asset".equals(type)) {
return source;
}
}
if (type != null && type.equals("fetch") && !StringUtils.isEmpty(format)) {
transformation().fetchFormat(format);
this.format = null;
}
String transformationStr = transformation().generate();
String signature = "";
String[] finalizedSource = finalizeSource(source, format, urlSuffix);
source = finalizedSource[0];
String sourceToSign = finalizedSource[1];
if (this.config.forceVersion && sourceToSign.contains("/") && !StringUtils.startWithVersionString(sourceToSign) &&
!httpSource && StringUtils.isEmpty(version)) {
version = "1";
}
if (version == null)
version = "";
else
version = "v" + version;
if (signUrl && (authToken == null || authToken.equals(AuthToken.NULL_AUTH_TOKEN))) {
SignatureAlgorithm signatureAlgorithm = longUrlSignature ? SHA256 : config.signatureAlgorithm;
String toSign = StringUtils.join(new String[]{transformationStr, sourceToSign}, "/");
toSign = StringUtils.removeStartingChars(toSign, '/');
toSign = StringUtils.mergeSlashesInUrl(toSign);
byte[] hash = Util.hash(toSign + this.config.apiSecret, signatureAlgorithm);
signature = Base64Coder.encodeURLSafeString(hash);
signature = "s--" + signature.substring(0, longUrlSignature ? 32 : 8) + "--";
}
String resourceType = this.resourceType;
if (resourceType == null) resourceType = "image";
String finalResourceType = finalizeResourceType(resourceType, type, urlSuffix, useRootPath, config.shorten);
String prefix = unsignedDownloadUrlPrefix(source, config.cloudName, config.privateCdn, config.cdnSubdomain, config.secureCdnSubdomain, config.cname, config.secure, config.secureDistribution);
String join = StringUtils.join(new String[]{prefix, finalResourceType, signature, transformationStr, version, source}, "/");
String url = StringUtils.mergeSlashesInUrl(join);
if (signUrl && authToken != null && !authToken.equals(AuthToken.NULL_AUTH_TOKEN)) {
try {
URL tempUrl = new URL(url);
String path = tempUrl.getPath();
String token = authToken.generate(path);
url = url + "?" + token;
} catch (MalformedURLException ignored) {
}
}
if (cloudinary.config.analytics != null && cloudinary.config.analytics) {
try {
URL tempUrl = new URL(url);
// if any other query param already exist on the URL do not add analytics query param.
if (tempUrl.getQuery() == null) {
String path = tempUrl.getPath();
url = url + "?" + cloudinary.analytics.toQueryParam();
}
} catch (MalformedURLException ignored) {
}
}
return url;
}
private String[] finalizeSource(String source, String format, String urlSuffix) {
source = StringUtils.mergeSlashesInUrl(source);
String[] result = new String[2];
String sourceToSign;
if (StringUtils.isHttpUrl(source)) {
source = SmartUrlEncoder.encode(source);
sourceToSign = source;
} else {
try {
source = SmartUrlEncoder.encode(URLDecoder.decode(source.replace("+", "%2B"), "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
sourceToSign = source;
if (StringUtils.isNotBlank(urlSuffix)) {
if (urlSuffix.contains(".") || urlSuffix.contains("/")) {
throw new IllegalArgumentException("url_suffix should not include . or /");
}
source = source + "/" + urlSuffix;
}
if (StringUtils.isNotBlank(format)) {
source = source + "." + format;
sourceToSign = sourceToSign + "." + format;
}
}
result[0] = source;
result[1] = sourceToSign;
return result;
}
public String finalizeResourceType(String resourceType, String type, String urlSuffix, boolean useRootPath, boolean shorten) {
if (type == null) {
type = "upload";
}
if (!StringUtils.isBlank(urlSuffix)) {
if (resourceType.equals("image") && type.equals("upload")) {
resourceType = "images";
type = null;
} else if (resourceType.equals("image") && type.equals("private")) {
resourceType = "private_images";
type = null;
} else if (resourceType.equals("image") && type.equals("authenticated")) {
resourceType = "authenticated_images";
type = null;
} else if (resourceType.equals("raw") && type.equals("upload")) {
resourceType = "files";
type = null;
} else if (resourceType.equals("video") && type.equals("upload")) {
resourceType = "videos";
type = null;
} else {
throw new IllegalArgumentException("URL Suffix only supported for image/upload, image/private, raw/upload, image/authenticated and video/upload");
}
}
if (useRootPath) {
if ((resourceType.equals("image") && type.equals("upload")) || (resourceType.equals("images") && StringUtils.isBlank(type))) {
resourceType = null;
type = null;
} else {
throw new IllegalArgumentException("Root path only supported for image/upload");
}
}
if (shorten && resourceType.equals("image") && type.equals("upload")) {
resourceType = "iu";
type = null;
}
String result = resourceType;
if (type != null) {
result += "/" + type;
}
return result;
}
public String unsignedDownloadUrlPrefix(String source, String cloudName, boolean privateCdn, boolean cdnSubdomain, Boolean secureCdnSubdomain, String cname, boolean secure, String secureDistribution) {
if (this.config.cloudName.startsWith("/")) {
return "/res" + this.config.cloudName;
}
boolean sharedDomain = !this.config.privateCdn;
String prefix;
if (this.config.secure) {
if (StringUtils.isEmpty(this.config.secureDistribution) || this.config.secureDistribution.equals(Cloudinary.OLD_AKAMAI_SHARED_CDN)) {
secureDistribution = this.config.privateCdn ? this.config.cloudName + "-res.cloudinary.com" : Cloudinary.SHARED_CDN;
}
if (!sharedDomain) {
sharedDomain = secureDistribution.equals(Cloudinary.SHARED_CDN);
}
if (secureCdnSubdomain == null && sharedDomain) {
secureCdnSubdomain = this.config.cdnSubdomain;
}
if (secureCdnSubdomain != null && secureCdnSubdomain == true) {
secureDistribution = this.config.secureDistribution.replace("res.cloudinary.com", "res-" + shard(source) + ".cloudinary.com");
}
prefix = "https://" + secureDistribution;
} else if (StringUtils.isNotBlank(this.config.cname)) {
String subdomain = this.config.cdnSubdomain ? "a" + shard(source) + "." : "";
prefix = "http://" + subdomain + this.config.cname;
} else {
String protocol = "http://";
cloudName = this.config.privateCdn ? this.config.cloudName + "-" : "";
String res = "res";
String subdomain = this.config.cdnSubdomain ? "-" + shard(source) : "";
String domain = ".cloudinary.com";
prefix = StringUtils.join(new String[]{protocol, cloudName, res, subdomain, domain}, "");
}
if (sharedDomain) {
prefix += "/" + this.config.cloudName;
}
return prefix;
}
private String shard(String input) {
CRC32 crc32 = new CRC32();
crc32.update(Util.getUTF8Bytes(input));
return String.valueOf((crc32.getValue() % 5 + 5) % 5 + 1);
}
@SuppressWarnings("unchecked")
public String imageTag(String source) {
return imageTag(source, ObjectUtils.emptyMap());
}
public String imageTag(Map attributes) {
return imageTag(null, attributes);
}
public String imageTag(String source, Map attributes) {
String url = generate(source);
attributes = new TreeMap(attributes); // Make sure they
// are ordered.
if (transformation().getHtmlHeight() != null)
attributes.put("height", transformation().getHtmlHeight());
if (transformation().getHtmlWidth() != null)
attributes.put("width", transformation().getHtmlWidth());
boolean hiDPI = transformation().isHiDPI();
boolean responsive = transformation().isResponsive();
if (!config.clientHints && (hiDPI || responsive)) {
attributes.put("data-src", url);
String extraClass = responsive ? "cld-responsive" : "cld-hidpi";
attributes.put("class", (StringUtils.isBlank(attributes.get("class")) ? "" : attributes.get("class") + " ") + extraClass);
String responsivePlaceholder = attributes.remove("responsive_placeholder");
if ("blank".equals(responsivePlaceholder)) {
responsivePlaceholder = CL_BLANK;
}
url = responsivePlaceholder;
}
StringBuilder builder = new StringBuilder();
builder.append(" attr : attributes.entrySet()) {
builder.append(" ").append(attr.getKey()).append("='").append(attr.getValue()).append("'");
}
builder.append("/>");
return builder.toString();
}
public String videoTag() {
return videoTag("", new HashMap());
}
public String videoTag(String source) {
return videoTag(source, new HashMap());
}
public String videoTag(Map attributes) {
return videoTag("", attributes);
}
private String finalizePosterUrl(String source) {
String posterUrl = null;
if (this.posterUrl != null) {
posterUrl = this.posterUrl.generate();
} else if (this.posterTransformation != null) {
posterUrl = this.clone().format("jpg").transformation(new Transformation(this.posterTransformation))
.generate(source);
} else if (this.posterSource != null) {
if (!StringUtils.isEmpty(this.posterSource))
posterUrl = this.clone().format("jpg").generate(this.posterSource);
} else {
posterUrl = this.clone().format("jpg").generate(source);
}
return posterUrl;
}
private void appendVideoSources(StringBuilder html, String source, String sourceType) {
Url sourceUrl = this.clone();
if (this.sourceTransformation != null) {
Transformation transformation = this.transformation;
Transformation sourceTransformation = null;
if (this.sourceTransformation.get(sourceType) != null)
sourceTransformation = new Transformation(this.sourceTransformation.get(sourceType));
if (transformation == null) {
transformation = sourceTransformation;
} else if (sourceTransformation != null) {
transformation = transformation.chainWith(sourceTransformation);
}
sourceUrl.transformation(transformation);
}
String src = sourceUrl.format(sourceType).generate(source);
String videoType = sourceType;
if (sourceType.equals("ogv"))
videoType = "ogg";
String mimeType = "video/" + videoType;
html.append("");
}
public String videoTag(String source, Map attributes) {
if (StringUtils.isEmpty(source))
source = this.source;
if (StringUtils.isEmpty(source))
source = publicId;
if (StringUtils.isEmpty(source))
throw new IllegalArgumentException("must supply source or public id");
source = VIDEO_EXTENSION_RE.matcher(source).replaceFirst("");
if (this.resourceType == null) this.resourceType = "video";
attributes = new TreeMap(attributes); // Make sure they are ordered.
String[] sourceTypes = this.sourceTypes;
if (sourceTypes == null) {
sourceTypes = DEFAULT_VIDEO_SOURCE_TYPES;
}
String posterUrl = this.finalizePosterUrl(source);
if (!StringUtils.isEmpty(posterUrl))
attributes.put("poster", posterUrl);
StringBuilder html = new StringBuilder().append(" 1;
if (!multiSource) {
url = generate(source + "." + sourceTypes[0]);
attributes.put("src", url);
} else {
generate(source);
}
if (this.transformation.getHtmlHeight() != null)
attributes.put("height", this.transformation.getHtmlHeight());
if (attributes.containsKey("html_height"))
attributes.put("height", attributes.remove("html_height"));
if (this.transformation.getHtmlWidth() != null)
attributes.put("width", this.transformation.getHtmlWidth());
if (attributes.containsKey("html_width"))
attributes.put("width", attributes.remove("html_width"));
for (Map.Entry attr : attributes.entrySet()) {
html.append(" ").append(attr.getKey());
if (attr.getValue() != null) {
String value = ObjectUtils.asString(attr.getValue());
html.append("='").append(value).append("'");
}
}
html.append(">");
if (multiSource) {
for (String sourceType : sourceTypes) {
this.appendVideoSources(html, source, sourceType);
}
}
if (this.fallbackContent != null)
html.append(this.fallbackContent);
html.append(" ");
return html.toString();
}
public String generateSpriteCss(String source) {
this.type = "sprite";
if (!source.endsWith(".css"))
this.format = "css";
return generate(source);
}
public Url source(String source) {
this.source = source;
return this;
}
public Url source(StoredFile source) {
if (source.getResourceType() != null)
this.resourceType = source.getResourceType();
if (source.getType() != null)
this.type = source.getType();
if (source.getVersion() != null)
this.version = source.getVersion().toString();
this.format = source.getFormat();
this.source = source.getPublicId();
return this;
}
}