/** * */ package org.gcube.portlets.user.urlshortener; /** * @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it * @Jun 28, 2013 * */ import static org.gcube.resources.discovery.icclient.ICFactory.clientFor; import static org.gcube.resources.discovery.icclient.ICFactory.queryFor; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import java.util.Map; import org.gcube.common.encryption.encrypter.StringEncrypter; import org.gcube.common.resources.gcore.ServiceEndpoint; import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint; import org.gcube.common.resources.gcore.ServiceEndpoint.Property; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.resources.discovery.client.api.DiscoveryClient; import org.gcube.resources.discovery.client.queries.impl.XQuery; import org.json.JSONObject; import org.json.JSONTokener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The Class UrlShortener. * * @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it) * * May 31, 2019 */ public final class UrlShortener { protected static final String APPLICATION_JSON = "application/json"; protected static final String LONG_DYNAMIC_LINK = "longDynamicLink"; protected static final String SHORTENER = "HTTP-URL-Shortener-DL"; protected static final String KEY = "key"; protected static final String DYNAMIC_LINK = "dynamic-link"; protected static final String SUFFIX = "suffix"; private static String shortnerServiceUrl = null; private static String decryptedKEY = null; private static String suffixOption = null; private static String dynamicLink = null; protected static Logger logger = LoggerFactory.getLogger(UrlShortener.class); private String uriRequest; private boolean isAvailable = false; /** * Instantiates a new url shortener. * It uses the scope from {@link ScopeProvider#instance} to read the Runtime Resource {@link UrlShortener#SHORTENER}} * @throws Exception the exception */ public UrlShortener() throws Exception{ this(ScopeProvider.instance.get()); } /** * Instantiates a new url shortener. * * @param scope the scope * @throws Exception the exception */ private UrlShortener(String scope) throws Exception { try{ logger.info("Trying to read the Runtime Resource with name {}, in the scope: {}",SHORTENER,scope); if(scope==null || scope.isEmpty()){ String msg = "Scope is null or empty! You must set the scope into: "+ScopeProvider.instance.getClass(); throw new Exception(msg); } XQuery query = queryFor(ServiceEndpoint.class); query.addCondition("$resource/Profile/Name/text() eq '"+SHORTENER+"'").setResult("$resource/Profile/AccessPoint"); DiscoveryClient client = clientFor(AccessPoint.class); List endpoints = client.submit(query); if (endpoints.size() == 0){ isAvailable = false; logger.warn("Runtime Resource " +SHORTENER+ " not found"); throw new Exception("No Runtime Resource with name: "+SHORTENER+" is available in the scope: "+scope); } AccessPoint shortnerAP = endpoints.get(0); if(shortnerAP!=null){ shortnerServiceUrl = shortnerAP.address(); //READING THE PROPERTIES Map propertiesMap = shortnerAP.propertyMap(); if(propertiesMap==null || propertiesMap.size()==0) { throw new Exception("You need to add the configurations as properties to "+SHORTENER); } //READING KEY String encrKey = readPropertyValue(propertiesMap, KEY); logger.debug("Read property with name {} and value {}", KEY, encrKey); if(encrKey!=null) { decryptedKEY = StringEncrypter.getEncrypter().decrypt(encrKey); logger.debug("Decrypted {}: {}+++MASKED-KEY+++", KEY, decryptedKEY.substring(0, decryptedKEY.length()-10)); } dynamicLink = readPropertyValue(propertiesMap, DYNAMIC_LINK); logger.debug("Read property with name {} and value {}", DYNAMIC_LINK, dynamicLink); suffixOption = readPropertyValue(propertiesMap, SUFFIX); logger.debug("Read property with name {} and value {}", SUFFIX, suffixOption); } if(shortnerServiceUrl==null || decryptedKEY==null) { String error = "The access point in the RR: "+SHORTENER+" for scope "+scope+" is not available correctly. Impossible to read the service URL or decrypt the password"; logger.warn(error); throw new Exception(error); } logger.trace("The shortner service URL is: {}",shortnerServiceUrl); String getParam = ""; //ACTIVE THIS AFTER RELEASE if(decryptedKEY!=null && !decryptedKEY.isEmpty()){ getParam = "?"+KEY +"="+decryptedKEY; //getParam = "?"+KEY +"=AIzaSyCRGq1oO76Xi-pQEMPbdGWIUGVwueVbE5Y"; } uriRequest = shortnerServiceUrl+getParam; logger.info("HTTP-URL-Shortener found in scope {}, uriRequest: {}... KEY MASKED",scope, uriRequest.substring(0,uriRequest.length()-10)); isAvailable = true; }catch (Exception e) { logger.error("An error occurred reading Runtime Resource for name: "+SHORTENER+", the scope is: "+scope, e); isAvailable = false; throw new Exception("No "+SHORTENER+" available!"); } } /** * Read property value. * * @param propertiesMap the properties map * @param key the key * @return the string * @throws Exception the exception */ public String readPropertyValue(Map propertiesMap, String key) throws Exception{ Property theProperty = propertiesMap.get(key)!=null?propertiesMap.get(key):null; if(theProperty==null) throw new Exception("You need to add the "+key+" Property in the "+SHORTENER); return theProperty.value(); } /** * Shorten. * * @param longUrl the long url * @return a shorten url * @throws Exception the exception */ public String shorten(String longUrl) throws Exception{ if (longUrl == null) { return longUrl; } try { logger.debug("shorten the input longUrl: "+longUrl); URL url = new URL(uriRequest); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", APPLICATION_JSON); JSONObject jsonObj = new JSONObject(); //jsonObj.put(LONG_URL, longUrl); String toLongURL = String.format("%s?link=%s",dynamicLink,longUrl); jsonObj.put(LONG_DYNAMIC_LINK, toLongURL); JSONObject jsonObjSuffix = null; //suffixOption = null; if(suffixOption!=null) { jsonObjSuffix = new JSONObject(suffixOption); }else { //DEFAULT OPTION IS SHORT jsonObjSuffix = new JSONObject(); jsonObjSuffix.put("option", "SHORT"); } jsonObj.put("suffix", jsonObjSuffix); // //ACTIVE THIS AFTER RELEASE // if(paramKeyValue!=null && !paramKeyValue.isEmpty()){ // jsonObj.put(KEY, paramKeyValue); // } logger.debug("Performing POST request to URI: {}+++MASKED-KEY+++",uriRequest.substring(0,uriRequest.length()-10)); logger.debug("the body contains the JSON request: \n{}",jsonObj.toString(3)); OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream()); wr.write(jsonObj.toString()); wr.flush(); BufferedReader rd = new BufferedReader(new InputStreamReader(connection.getInputStream())); JSONTokener tokener = new JSONTokener(rd); JSONObject jsonObject = new JSONObject(tokener); logger.debug("response contains the json: "+jsonObject.toString()); wr.close(); rd.close(); return (String) jsonObject.get("shortLink"); //it is the SHORT URL } catch (MalformedURLException e) { logger.error("MalformedURLException error in UrlShortener", e); return longUrl; } catch (IOException e) { logger.error("IOException error in UrlShortener", e); return longUrl; } } /** * Checks if is available. * * @return true, if is available */ public boolean isAvailable() { return isAvailable; } /** * Gets the shortner server url. * * @return the shortner server url */ @Deprecated public static String getShortnerServerUrl() { return shortnerServiceUrl; } /** * Gets the shortner service url. * * @return the shortner service url */ public static String getShortnerServiceUrl() { return shortnerServiceUrl; } /** * Gets the key. * * @return the key */ public static String getKey() { return KEY; } /** * Gets the param key value. * * @return the param key value */ public static String getParamKeyValue() { return decryptedKEY; } /** * Gets the uri request. * * @return the uri request */ public String getUriRequest() { return uriRequest; } /** * Gets the suffix option. * * @return the suffix option */ public static String getSuffixOption() { return suffixOption; } /** * Gets the dynamic link. * * @return the dynamic link */ public static String getDynamicLink() { return dynamicLink; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("UrlShortener [uriRequest="); builder.append(uriRequest); builder.append(", isAvailable="); builder.append(isAvailable); builder.append("]"); return builder.toString(); } }