uri-resolver-manager/src/main/java/org/gcube/portlets/user/uriresolvermanager/UriResolverManager.java

412 lines
14 KiB
Java

/**
*
*/
package org.gcube.portlets.user.uriresolvermanager;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.portlets.user.uriresolvermanager.entity.Resolver;
import org.gcube.portlets.user.uriresolvermanager.entity.ServiceAccessPoint;
import org.gcube.portlets.user.uriresolvermanager.entity.ServiceParameter;
import org.gcube.portlets.user.uriresolvermanager.exception.IllegalArgumentException;
import org.gcube.portlets.user.uriresolvermanager.exception.NotImplementedException;
import org.gcube.portlets.user.uriresolvermanager.exception.UriResolverMapException;
import org.gcube.portlets.user.uriresolvermanager.readers.RuntimeResourceReader;
import org.gcube.portlets.user.uriresolvermanager.readers.UriResolverMapReader;
import org.gcube.portlets.user.uriresolvermanager.util.UrlEncoderUtil;
import org.gcube.portlets.user.uriresolvermanager.util.UrlEncoderUtil.URI_PART;
import org.gcube.portlets.user.urlshortener.UrlShortener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class UriResolverManager.
*
* @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it Sep 6, 2016
*/
public class UriResolverManager {
private UriResolverMapReader uriResolverMapReader;
private Map<String, Resolver> applicationTypes;
private String applicationType;
private RuntimeResourceReader reader;
/**
* A lock to prevent reader = null;
*/
private int usingReader = 0;
private ServiceAccessPoint serviceAccessPoint;
private Timer timer;
/**
* Lock reader.
*/
public synchronized void lockReader() {
usingReader++;
}
/**
* Release reader.
*/
public synchronized void releaseReader() {
usingReader--;
}
/**
* Count readers.
*
* @return the int
*/
public synchronized int countReaders() {
return usingReader;
}
public static final Logger LOG = LoggerFactory.getLogger(UriResolverManager.class);
/**
* Instantiates a new uri resolver manager. Precondition: set the scope into
* ScopeProvider {@link ScopeProvider#get()} The scope is used to look up the
* generic resource with name:
* {@link UriResolverMapReader#URI_RESOLVER_MAP_RESOURCE_NAME}, secondary type:
* {@link UriResolverMapReader#URIRESOLVERMAP_SECONDARY_TYPE} from IS to map
* ApplicationType with its Resolver
*
* @throws UriResolverMapException the uri resolver map exception
* @throws IllegalArgumentException the illegal argument exception
*/
public UriResolverManager() throws UriResolverMapException, IllegalArgumentException {
try {
String scope = ScopeProvider.instance.get();
LOG.info("UriResolverManager is using scope: " + scope + ", read from ScopeProvider");
if (scope == null)
throw new UriResolverMapException("Scope is null, set scope into ScopeProvider!");
this.uriResolverMapReader = new UriResolverMapReader();
this.applicationTypes = uriResolverMapReader.getApplicationTypes();
// this.setTimerUriResolverReader(RESET_DELAY, RESET_TIME);
} catch (UriResolverMapException e) {
LOG.error("UriResolverMapException: ", e);
throw e;
} catch (Exception e) {
LOG.error("UriResolverManager: ", e);
throw new UriResolverMapException("Map Application Type - Resources not found in IS");
}
}
/**
* Sets the application type.
*
* @param applicationType the applicationType to set
* @throws IllegalArgumentException the illegal argument exception
*/
public void setApplicationType(String applicationType) throws IllegalArgumentException {
if (!this.applicationTypes.containsKey(applicationType)) {
throw new IllegalArgumentException("Application type '" + applicationType
+ "' not found in Application Types: " + getApplicationTypes());
}
this.applicationType = applicationType;
}
/**
* Instance a UriResolverManager Precondition: set the scope provider
* {@link ScopeProvider.instance.get()} The scope is used to look up the generic
* resource {@link UriResolverMapReader#URI_RESOLVER_MAP} available in the
* infrastructure to map ApplicationType with its Resolver
*
* @param applicationType a (valid) key Application Type
* {@link UriResolverManager#getApplicationTypes()}
* @throws UriResolverMapException the uri resolver map exception
* @throws IllegalArgumentException the illegal argument exception
*/
public UriResolverManager(String applicationType) throws UriResolverMapException, IllegalArgumentException {
this();
setApplicationType(applicationType);
}
/**
* Gets the link.
*
* @param applicationType the application type
* @param parameters the map of the parameters sent as HTTP query string
* @param shortLink if true the link is shorted otherwise none
* @return the link
* @throws IllegalArgumentException the illegal argument exception
* @throws UriResolverMapException the uri resolver map exception
*/
public String getLink(String applicationType, Map<String, String> parameters, boolean shortLink)
throws IllegalArgumentException, UriResolverMapException {
this.applicationType = applicationType;
return getLink(parameters, shortLink);
}
/**
* Gets the link.
*
* @param parameters the map of the parameters sent as HTTP query
* string
* @param queryStringParameters the query string parameters
* @param shortLink if true the link is shortened otherwise none
* @return the link
* @throws IllegalArgumentException the illegal argument exception
* @throws UriResolverMapException the uri resolver map exception
*/
public String getLink(Map<String, String> parameters, boolean shortLink)
throws IllegalArgumentException, UriResolverMapException {
if (applicationType == null)
throw new IllegalArgumentException("Application type is null");
Resolver resolver = this.applicationTypes.get(applicationType);
LOG.debug("The resolver found is of kind: "+ resolver.getClass().getSimpleName());
String link = null;
if (parameters == null)
throw new IllegalArgumentException("Input Map parameters is null");
try {
// lockReader();
if (reader == null) {
LOG.info("Runtime Resource Reader is null, istancing...");
reader = new RuntimeResourceReader(resolver.getResourceName());
}
if (resolver.getEntryName() == null || resolver.getEntryName().isEmpty()) {
LOG.warn("The entryname to " + resolver.getResourceName()
+ " is null or empty, reading first Access Point!!");
serviceAccessPoint = reader.getServiceAccessPoints().get(0);
} else {
LOG.warn("Reading Access Point for Entry Name: " + resolver.getEntryName());
serviceAccessPoint = reader.getServiceAccessPointForEntryName(resolver.getEntryName());
if (serviceAccessPoint == null)
throw new UriResolverMapException("Entry Name " + resolver.getEntryName()
+ " not found in Resource name: " + resolver.getResourceName());
}
List<ServiceParameter> resourceParameters = serviceAccessPoint.getServiceParameters();
LOG.debug("Service parameters are: " + resourceParameters);
// CHECK PARAMETERS
for (ServiceParameter serviceParameter : resourceParameters) {
if (serviceParameter.isMandatory()) {
if (!parameters.containsKey(serviceParameter.getKey())) {
throw new IllegalArgumentException("Mandatory service key (parameter) '"
+ serviceParameter.getKey() + "' not found into input map");
}
}
}
String baseURI = serviceAccessPoint.getServiceUrl();
// SPECIALIZED IMPLEMENTATION OF RESOLVER
try {
link = resolver.getLink(baseURI, parameters);
LOG.debug("Read specialized getLink: " + link);
if (shortLink) {
link = resolver.shortLink(link, parameters);
}
return link;
} catch (NotImplementedException e) {
LOG.info("Specialized getLink not implemented, going to default implementation");
}
// GENERIC IMPLEMENTATION OF RESOLVER. DEFAULT IMPLEMENTATION APPLYING...
if (link == null) {
// not shortening so returning the link with the query string with only the
// parameters encoded
LOG.info("Specialized getLink is null, applying DEFAULT implementation via GET request on base URI and encoded query-string");
String queryString = UrlEncoderUtil.encodeQuery(parameters);
link = String.format("%s?%s", baseURI, queryString);
// LOG.info("returning base URI with encoded parameters in the query string: " +
// linkEncoded);
// return toReturn;
} else {
LOG.info("Specialized getLink is not null");
}
String linkNotShort = link;
LOG.info("Created HTTP link: " + link);
// Short link required
if (shortLink) {
try {
LOG.info("Short link requested, so encoding query string is required...");
URI_PART uriParts = UrlEncoderUtil.getURIParts(link);
if (uriParts.getQueryString() != null && !uriParts.getQueryString().isEmpty()) {
LOG.info("QueryString part " + uriParts.getQueryString() + " is not null, encoding it");
String queryStringEncoded = UrlEncoderUtil.encodeString(uriParts.getQueryString());
link = String.format("%s?%s", uriParts.getBaseURI(), queryStringEncoded);
}
LOG.info("Encoded link is: " + link);
LOG.info("Shortner starts..");
String shortenedLink = shortTheLink(link);
if (shortenedLink != null && shortenedLink.equals(link)) {
// here the short link and the input link are identical
// so the shortening did not work
// I'm returning the decoded link because it is directly consumable via browser
LOG.info("Short link is equal to long link, returning long link: " + linkNotShort);
link = linkNotShort;
} else {
// here the link is really shortened
LOG.debug("The link is really short, returning it");
link = shortenedLink;
}
} catch (Exception e) {
LOG.warn("An error occurred during link shortening: ", e);
// here I'm returning the decoded link in case of error on shortening it
link = linkNotShort;
}
}
} catch (IllegalArgumentException e) {
LOG.error("Uri Resolver IllegalArgumentException: ", e);
throw e;
} catch (Exception e) {
LOG.error("Uri Resolver Exception: ", e);
throw new UriResolverMapException("Uri Resolver error: " + e.getMessage());
}
LOG.info("Returning HTTP(s) link: " + link);
return link;
}
private String shortTheLink(String sourceLink) {
String toReturnLink = sourceLink;
try {
UrlShortener shortener = new UrlShortener();
String shortLink = shortener.shorten(sourceLink);
LOG.info("Short link is: " + shortLink);
toReturnLink = shortLink;
} catch (Exception e) {
LOG.warn("Returning source link, an error occurred during link shortening: ", e);
}
return toReturnLink;
}
/**
* Gets the application types.
*
* @return the Application Types available
*/
public Set<String> getApplicationTypes() {
return this.applicationTypes.keySet();
}
/**
* Discovery service parameters.
*
* @param resolver the resolver
* @return the list
* @throws IllegalArgumentException the illegal argument exception
* @throws Exception the exception
*/
public List<ServiceParameter> discoveryServiceParameters(Resolver resolver)
throws IllegalArgumentException, Exception {
try {
String scope = ScopeProvider.instance.get();
LOG.info("DiscoveryServiceParameters is using scope: " + scope + ", read from ScopeProvider");
if (scope == null)
throw new UriResolverMapException("Scope is null, set scope into ScopeProvider!");
if (resolver == null)
throw new IllegalArgumentException("Resolver is null, set Resolver");
RuntimeResourceReader reader = new RuntimeResourceReader(resolver.getResourceName());
ServiceAccessPoint serviceAccessPoint = null;
if (resolver.getEntryName() == null || resolver.getEntryName().isEmpty()) {
LOG.warn("The entryname to " + resolver.getResourceName()
+ " is null or empty, reading first Access Point!!");
serviceAccessPoint = reader.getServiceAccessPoints().get(0);
} else {
LOG.info("Reading Access Point for entryname: " + resolver.getEntryName());
serviceAccessPoint = reader.getServiceAccessPointForEntryName(resolver.getEntryName());
if (serviceAccessPoint == null)
throw new UriResolverMapException("Entry Name " + resolver.getEntryName()
+ " not found in Resource name: " + resolver.getResourceName());
}
return serviceAccessPoint.getServiceParameters();
} catch (Exception e) {
LOG.error("Uri Resolver error: ", e);
throw new UriResolverMapException("Uri Resolver error: " + e.getMessage());
}
}
/**
* Gets the resolver.
*
* @param applicationType the application type
* @return the resolver
*/
public Resolver getResolver(String applicationType) {
return this.applicationTypes.get(applicationType);
}
/**
* Gets the capabilities.
*
* @return a map Application Type - Resolver
*/
public Map<String, Resolver> getCapabilities() {
return this.applicationTypes;
}
/**
* Sets the timer uri resolver reader.
*
* @param delay the delay
* @param period the period
*/
public void setTimerUriResolverReader(long delay, long period) {
cancelTimerUriResolverReader();
timer = new Timer(true);
timer.schedule(new TimerTask() {
@Override
public void run() {
LOG.info("Timer Reset Runtime Resource running..");
int counters = countReaders();
if (counters == 0) {
LOG.info("Reader not locked, resetting");
reader = null;
} else
LOG.info("Reader locked, counters is/are:" + counters + ", skipping");
}
}, delay, period);
}
/**
* Cancel timer uri resolver reader.
*/
public void cancelTimerUriResolverReader() {
if (timer != null)
timer.cancel();
}
/**
* Invalid uri resolver reader.
*/
public void invalidUriResolverReader() {
reader = null;
}
}