/*
* Copyright 2013-2014, ApiFest project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.apifest;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.apifest.api.BasicAction;
import com.apifest.api.BasicFilter;
import com.apifest.api.MappingAction;
import com.apifest.api.MappingEndpoint;
import com.apifest.api.MappingException;
import com.apifest.api.ResponseFilter;
/**
* Holds the configuration for a mapping version.
*
* @author Rossitsa Borissova
*/
public class MappingConfig implements Serializable {
private static final long serialVersionUID = 5553036783446791217L;
private static Logger log = LoggerFactory.getLogger(MappingConfig.class);
private Map<MappingPattern, MappingEndpoint> mappings = new HashMap<MappingPattern, MappingEndpoint>();
private Map<String, String> actions = new HashMap<String, String>();
private Map<String, String> filters = new HashMap<String, String>();
private Map<String, String> errors = new HashMap<String, String>();
public void setMappings(Map<MappingPattern, MappingEndpoint> mappings) {
this.mappings = mappings;
}
public void setActions(Map<String, String> actions) {
this.actions = actions;
}
public void setFilters(Map<String, String> filters) {
this.filters = filters;
}
public void setErrors(Map<String, String> errors) {
this.errors = errors;
}
protected Map<MappingPattern, MappingEndpoint> getMappings() {
return mappings;
}
protected Map<String, String> getActions() {
return actions;
}
protected Map<String, String> getFilters() {
return filters;
}
protected Map<String, String> getErrors() {
return errors;
}
public String getErrorMessage(int code) {
if (getErrors().get(String.valueOf(code)) != null) {
return getErrors().get(String.valueOf(code));
}
return null;
}
/**
* Returns MappingEndpoint corresponding to an URI.
*
* @param uri external uri
* @return <code>MappingEndpoint</code> that corresponds to the passed URI
*/
public MappingEndpoint getMappingEndpoint(String uri, String method) {
String rawUri = getUriWithoutParams(uri);
Set<MappingPattern> patterns = getMappings().keySet();
for (MappingPattern p : patterns) {
Matcher m = p.getPattern().matcher(rawUri.trim());
if (m.find() && p.getMethod().equals(method)) {
MappingEndpoint cur = getMappings().get(p);
String newUri = cur.getInternalEndpoint();
// replace variables with their values
if (cur.getVarName() != null) {
String [] varNames = cur.getVarName().split(" ");
if (newUri.contains("{") && m.groupCount() >= 1) {
for (int i = 0; i < varNames.length; i++) {
String varValue = m.group(i + 1);
newUri = newUri.replace("{" + varNames[i] + "}", varValue);
}
}
}
MappingEndpoint result = new MappingEndpoint(cur.getExternalEndpoint(), newUri, cur.getMethod(), cur.getAuthType(), cur.getScope(), cur.getAction(), cur.getFilter(),
cur.getVarExpression(), cur.getVarName(), cur.getBackendHost(), cur.getBackendPort(), cur.getCustomProperties());
return result;
}
}
return null;
}
private String getUriWithoutParams(String uri) {
String rawUri = uri;
try {
URI u = new URI(uri);
rawUri = u.getRawPath();
} catch (URISyntaxException e) {
log.error("URI syntax is not valid, {}", uri);
}
return rawUri;
}
/**
* Returns instance of BasicAction that corresponds to the passed mappingAction.
*
* @param mappingAction <code>MappingAction</code>
* @return instance of <code>BasicAction</code>
*/
public BasicAction getAction(MappingAction mappingAction) throws MappingException {
BasicAction action = null;
String actionClass;
if (mappingAction.getActionClassName() != null) {
actionClass = mappingAction.getActionClassName();
} else {
actionClass = getActions().get(mappingAction.getName());
}
if (actionClass == null) {
throw new MappingException("action " + mappingAction.getName() + " not mapped to class");
}
Class<?> clazz;
try {
// load class from custom jar
clazz = ConfigLoader.loadCustomClass(actionClass);
} catch (ClassNotFoundException e) {
try {
clazz = Class.forName(actionClass);
} catch (ClassNotFoundException e1) {
throw new MappingException("cannot instantiate action class " + actionClass, e1);
}
}
try {
action = (BasicAction) clazz.newInstance();
} catch (InstantiationException e) {
throw new MappingException("cannot instantiate action class " + actionClass, e);
} catch (IllegalAccessException e) {
throw new MappingException("cannot instantiate action class " + actionClass, e);
}
return action;
}
/**
* Returns instance of BasicFilter that corresponds to the response filter.
*
* @param responseFilter response filter
* @return BasicFilter instance
*/
public BasicFilter getFilter(ResponseFilter responseFilter) throws MappingException {
BasicFilter filter = null;
String filterClass;
if (responseFilter.getFilterClassName() != null) {
filterClass = responseFilter.getFilterClassName();
} else {
filterClass = getFilters().get(responseFilter.getName());
}
if (filterClass == null) {
throw new MappingException("filter " + responseFilter.getName() + " not mapped to class");
}
Class<?> clazz;
try {
// load class from custom jar
clazz = ConfigLoader.loadCustomClass(filterClass);
} catch (ClassNotFoundException e) {
try {
clazz = Class.forName(filterClass);
} catch (ClassNotFoundException e1) {
throw new MappingException("cannot instantiate filter class " + filterClass, e1);
}
}
try {
filter = (BasicFilter) clazz.newInstance();
} catch (InstantiationException e) {
throw new MappingException("cannot instantiate filter class " + filterClass, e);
} catch (IllegalAccessException e) {
throw new MappingException("cannot instantiate filter class " + filterClass, e);
}
return filter;
}
public MappingConfig mergeConfig(MappingConfig config) throws MappingException {
Map<MappingPattern, MappingEndpoint> newMappings = config.getMappings();
for (MappingPattern pattern : newMappings.keySet()) {
if (!mappings.containsKey(pattern)) {
continue;
} else {
throw new MappingException("external path " + pattern.getMethod() + " " + pattern.getPattern().toString() + " is duplicated in mappings");
}
}
mappings.putAll(config.getMappings());
actions.putAll(config.getActions());
filters.putAll(config.getFilters());
errors.putAll(config.getErrors());
return this;
}
}