/**
*
*/
package org.minnal.core;
import static org.minnal.utils.http.HttpUtil.structureUrl;
import io.netty.handler.codec.http.HttpRequest;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import org.minnal.core.config.ApplicationConfiguration;
import org.minnal.utils.Comparators;
import org.minnal.utils.http.HttpUtil;
/**
* Manages the mapping between mount path and application. Resolves the application mount paths to absolute path of the container.
* <p/>
* The request url will be mapped as the following,
* <pre>
* http://localhost:3000/<base-path>/<application-path>/<resource-path>
* <p/>
*
* @author ganeshs
*/
public class ApplicationMapping {
private Map<String, Application<ApplicationConfiguration>> applications = new HashMap<String, Application<ApplicationConfiguration>>();
private String basePath;
/**
* Constructor with base path of the container. Expects a path starting with '/' character. Defaults to '/' if path is null or empty.
* Structures the url to ensure it starts with '/' and ends without a '/'
*
* @param basePath the base path of the container
*/
public ApplicationMapping(String basePath) {
this.basePath = structureUrl(basePath);
}
/**
* Maps application to its mount path. If the mount path already exists or if the application is already mapped to another mount path,
* throws an exception
*
* @param application
* @param mountPath
*/
public void addApplication(Application<ApplicationConfiguration> application) {
String mountPath = structureUrl(application.getConfiguration().getBasePath());
String path = getAbsolutePath(mountPath);
if (applications.containsKey(path)) {
throw new IllegalArgumentException("Mount path - " + mountPath + " already exists. Either change the application base path or override it in container");
}
if (applications.containsValue(application)) {
throw new IllegalArgumentException("Application - " + application + " is already mounted on a different mount path");
}
application.setPath(HttpUtil.createURI(path));
applications.put(path, application);
}
/**
* Unmaps a mount path from the application. Throws an exception if the mount path doesn't exist
*
* @param mountPath
* @return the application that's unmapped from the mount path
*/
public Application<ApplicationConfiguration> removeApplication(String mountPath) {
mountPath = structureUrl(mountPath);
String path = getAbsolutePath(mountPath);
if (! applications.containsKey(path)) {
throw new IllegalArgumentException("Mount path - " + mountPath+ " doesn't exist");
}
return applications.remove(path);
}
/**
* Resolves the request to an application by mapping the request url to the application path.
*
* @param request
* @return the application that this request resolves to
*/
public Application<ApplicationConfiguration> resolve(HttpRequest request) {
String path = request.getUri();
for (Entry<String, Application<ApplicationConfiguration>> entry : getSortedApplications().entrySet()) {
if (path.startsWith(entry.getKey())) {
return entry.getValue();
}
}
return null;
}
/**
* Returns all the applications managed by the container
*
* @return
*/
public Collection<Application<ApplicationConfiguration>> getApplications() {
return applications.values();
}
/**
* @return the basePath
*/
public String getBasePath() {
return basePath;
}
/**
* Returns the absolute path for the given mount path
*
* @param mountPath
* @return
*/
private String getAbsolutePath(String mountPath) {
return basePath + mountPath;
}
private Map<String, Application<ApplicationConfiguration>> getSortedApplications() {
Map<String, Application<ApplicationConfiguration>> applications =
new TreeMap<String, Application<ApplicationConfiguration>>(Comparators.LENGTH_COMPARATOR);
applications.putAll(this.applications);
return applications;
}
}