/**
* XWeb project
* Created by Hamed Abdollahpour
* https://github.com/abdollahpour/xweb
*/
package ir.xweb.module;
import java.io.IOException;
import java.io.Reader;
import java.lang.IllegalArgumentException;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import ir.xweb.util.Tools;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
public class Module {
private final Manager manager;
private final ModuleInfo info;
private final ModuleParam properties;
private final RoleManager roleManager;
private final List<String> requireParams;
private Map<String, ModuleInfoValidator> validators = new HashMap<String, ModuleInfoValidator>();
public Module(
final Manager manager,
final ModuleInfo info,
final ModuleParam properties) throws ModuleException {
if(manager == null) {
throw new IllegalArgumentException("null manager");
}
this.manager = manager;
this.info = info;
this.properties = properties;
roleManager = new RoleManager(info.getRoles());
validators = new HashMap<String, ModuleInfoValidator>(info.getValidators().size());
requireParams = new ArrayList<String>(validators.size());
for(ModuleInfoValidator validator:info.getValidators()) {
validators.put(validator.getParam(), validator);
if(validator.isRequire()) {
requireParams.add(validator.getParam());
}
}
}
public void init(ServletContext context) {
}
public void destroy() {
}
public ModuleInfo getInfo() {
return info;
}
public void process(
final ServletContext context,
final HttpServletRequest request,
final HttpServletResponse response,
final String role) throws IOException {
final String contentType = request.getHeader("Content-Type");
final HashMap<String, Object> params = new HashMap<String, Object>();
final HashMap<String, FileItem> files = new HashMap<String, FileItem>();
ModuleParam moduleParam = null;
if(contentType != null) {
final String ct = contentType.toLowerCase();
if(ct.indexOf("multipart/form-data") > -1) {
try {
List<?> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
for (Object o : items) {
FileItem item = (FileItem)o;
if (item.isFormField()) {
String fieldname = item.getFieldName();
String fieldvalue = item.getString();
// DAMN! There's problem for Apache commons-fileupload && UTF-8. We should to fix it manually
// http://stackoverflow.com/questions/546365/utf-8-text-is-garbled-when-form-is-posted-as-multipart-form-data
fieldname = new String (fieldname.getBytes ("iso-8859-1"), "UTF-8");
fieldvalue = new String (fieldvalue.getBytes ("iso-8859-1"), "UTF-8");
final Object old = params.get(fieldname);
params.put(fieldname, old == null ? fieldvalue : old + "," + fieldvalue);
} else {
final String filename = item.getName();
/** FormData for HTML5 will send files but with empty files name! **/
if(filename != null && filename.length() > 0) {
String fieldname = item.getFieldName();
files.put(fieldname, item);
}
}
}
} catch (FileUploadException e) {
}
}
else if(ct.equals("application/json")) {
try {
final Reader reader = request.getReader();
JSONTokener tokenizer = new JSONTokener(reader);
final JSONObject object = new JSONObject(tokenizer);
moduleParam = json2module(object);
} catch (Exception ex) {
throw new ModuleException("Error to parse json post", ex);
}
}
}
final Enumeration<?> names = request.getParameterNames();
if(names != null) {
while(names.hasMoreElements()) {
final String name = names.nextElement().toString();
final String[] value = request.getParameterValues(name);
params.put(name, Tools.implode(",", value));
}
}
if(moduleParam == null) {
moduleParam = new ModuleParam(params);
}
// validate params
List<String> requires = new ArrayList<String>(requireParams);
for(String name:params.keySet()) {
final ModuleInfoValidator validator = validators.get(name);
if(validator != null) {
moduleParam.validate(name, validator.getRegex(), validator.isRequire());
requires.remove(name);
}
}
if(requires.size() > 0) {
throw new IllegalArgumentException("Parameter needed: " + requireParams.get(0));
}
// Check for roles
try {
// We don't apply any authentication to schedule tasks
if(!(request instanceof ScheduleRequest)) {
if (!roleManager.hasPermission(params, role)) {
if (role == null) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "You do not have permission to access with this role: " + role);
} else {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "You do not have permission to access with this role: " + role);
}
return;
}
}
} catch (Exception ex) {
throw new IOException(ex);
}
process(context, request, response, moduleParam, files);
response.flushBuffer();
}
public void process(
ServletContext context,
HttpServletRequest request,
HttpServletResponse response,
ModuleParam param,
Map<String, FileItem> files) throws IOException {
}
public void doFilter(
ServletContext context,
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(request, response);
}
public void initFilter(FilterConfig filterConfig) throws ServletException {
}
public void destroyFilter() {
}
/*public boolean hasPermission(ModuleParam params, String role) {
if(info != null && info.getRoles() != null) {
for(Role r:info.getRoles()) {
if(r.actions == null) {
if(r.name.equals(role)) {
return true;
}
} else {
if(r.name.equals(role)) {
return action == null || r.actions.contains(action);
}
}
}
}
return false;
}*/
private ModuleParam json2module(final JSONObject object) throws JSONException {
final ModuleParam p = new ModuleParam();
for(Iterator k = object.keys(); k.hasNext();) {
String key = k.next().toString();
final Object o = object.get(key);
if(o instanceof JSONObject) {
p.put(key, json2module((JSONObject)o));
}
else if(o instanceof JSONArray) {
p.put(key, json2module((JSONArray)o));
}
else {
p.put(key, o);
}
}
return p;
}
private Collection json2module(final JSONArray array) throws JSONException {
if(array.length() > 0) {
final ArrayList list = new ArrayList();
for(int i=0; i<array.length(); i++) {
list.add(array.get(i));
}
return list;
}
return Collections.emptyList();
}
public RoleManager getRoleManager() {
return roleManager;
}
public ServletContext getContext() {
return manager.getContext();
}
public Manager getManager() {
return manager;
}
public ModuleParam getProperties() {
return this.properties;
}
//public boolean redirectAuthFail() {
// return false;
//}
}