/** * Copyright (C) 2007 - 2016 52°North Initiative for Geospatial Open Source * Software GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * * If the program is linked with libraries which are licensed under one of * the following licenses, the combination of the program with the linked * library is not considered a "derivative work" of the program: * * • Apache License, version 2.0 * • Apache Software License, version 1.0 * • GNU Lesser General Public License, version 3 * • Mozilla Public License, versions 1.0, 1.1 and 2.0 * • Common Development and Distribution License (CDDL), version 1.0 * * Therefore the distribution of the program linked with libraries licensed * under the aforementioned licenses, is permitted by the copyright holders * if the distribution is compliant with both the GNU General Public * License version 2 and the aforementioned licenses. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. */ package org.n52.wps.webadmin; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.net.URLDecoder; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import org.apache.commons.lang.SystemUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.n52.wps.PropertyDocument.Property; import org.n52.wps.commons.WPSConfig; /** * This Bean handles the fileupload of the xml configuration file * * @author Florian van Keulen */ public class ConfigUploadBean { private static transient Logger LOGGER = LoggerFactory.getLogger(ConfigUploadBean.class); private String savePath, filepath, filename, xmlFilepath, xmlFilename, realSavePath, boundary; private final String filenamePrefix = "userConf_"; private int i, boundaryLength; private byte[] line; public String getFilenamePrefix() { return filenamePrefix; } private void setFilename(String s) { if (s == null) { return; } int pos = s.indexOf("filename=\""); if (pos != -1) { filepath = s.substring(pos + 10, s.length() - 1); // Windows browsers include the full path on the client // But Linux/Unix and Mac browsers only send the filename // test if this is from a Windows browser pos = filepath.lastIndexOf("\\"); if (pos != -1) { filename = filepath.substring(pos + 1); } else { filename = filepath; } } } private void setXMLFilename(String s) { if (s == null) { return; } int pos = s.indexOf("filename=\""); if (pos != -1) { xmlFilepath = s.substring(pos + 10, s.length() - 1); // Windows browsers include the full path on the client // But Linux/Unix and Mac browsers only send the filename // test if this is from a Windows browser pos = xmlFilepath.lastIndexOf("\\"); if (pos != -1) { xmlFilename = xmlFilepath.substring(pos + 1); } else { xmlFilename = xmlFilepath; } } } public void doUpload(HttpServletRequest request) throws IOException { savePath = WPSConfig.getConfigPath(); // get rid of the filename // How is the path on a windows machine? may be better using: // savePath = savePath.substring(0, savePath.length() - // "wps_config.xml".length()); savePath = savePath.substring(0, savePath.lastIndexOf(File.separator) + 1); ServletInputStream in = request.getInputStream(); line = new byte[128]; i = in.readLine(line, 0, 128); if (i < 3) { return; } boundaryLength = i - 2; int classnameupcoming = 4; boundary = new String(line, 0, boundaryLength); // -2 discards // the newline // character /* * the type of the uploaded file until now only processes (.java/.zip) * or R scripts are supported */ String type = ""; String realSavePath = ""; while (i != -1) { String newLine = new String(line, 0, i); System.out.println(newLine); if (newLine.contains("processName")) { type = "javaProcess"; // we set a flag to know that the next string is the fully // qualified classname classnameupcoming--; } else if (newLine.contains("rProcessName")) { type = "rScript"; // we set a flag to know that the next string is the fully // qualified classname classnameupcoming--; } if (classnameupcoming < 4) { classnameupcoming--; } if (classnameupcoming == 0) { // // then parse classname // String classname = newLine; // String[] classnameArr = classname.replace(".", // ",").split(","); // String classdir = new String(); // for (int c = 0; c < classnameArr.length - 1; c++) { // if (c == 0) { // classdir = classdir + classnameArr[c]; // } else { // classdir = classdir + File.separator + classnameArr[c]; // } // // } // realSavePath = new File(savePath).getParentFile() // + "/WEB-INF/classes/"; // realSavePath = realSavePath + classdir + File.separator; // new File(realSavePath).mkdirs(); try { handleUpload(in, type, newLine); break; } catch (Exception e) { e.printStackTrace(); } } if (newLine.startsWith("Content-Disposition: form-data; name=\"")) { if (newLine.contains("processDescriptionFile")) { if (newLine.indexOf("filename=\"") != -1) { setXMLFilename(new String(line, 0, i - 2)); if (xmlFilename == null) { return; } if (!xmlFilename.equals("")) { // this is the file content i = in.readLine(line, 0, 128); // next line i = in.readLine(line, 0, 128); // blank line i = in.readLine(line, 0, 128); newLine = new String(line, 0, i); // add the prefix to the filename PrintWriter pw = null; if (realSavePath.length() > 0) { pw = new PrintWriter(new BufferedWriter(new FileWriter((realSavePath == null ? "" : realSavePath) + xmlFilename))); } else { xmlFilename = filenamePrefix + xmlFilename; pw = new PrintWriter(new BufferedWriter(new FileWriter((savePath == null ? "" : savePath) + filename))); } while (i != -1 && !newLine.startsWith(boundary)) { // the problem is the last line of the file // content // contains the new line character. // So, we need to check if the current line is // the last line. i = in.readLine(line, 0, 128); if ((i == boundaryLength + 2 || i == boundaryLength + 4) // + // 4 // is // eof && (new String(line, 0, i).startsWith(boundary))) { pw.print(newLine.substring(0, newLine.length() - 2)); } else { pw.print(newLine); } newLine = new String(line, 0, i); } pw.close(); } } } if (newLine.contains("processFile")) { // we upload files not config docuemnts. Therefore store is // somewhere else. // realSavePath = new // File(savePath).getParentFile().getAbsolutePath()+"/WEB-INF/classes/"; /** * TODO: dir structure according to fully qual classname */ if (newLine.indexOf("filename=\"") != -1) { setFilename(new String(line, 0, i - 2)); if (filename == null) { return; } // this is the file content i = in.readLine(line, 0, 128); // next line i = in.readLine(line, 0, 128); // blank line i = in.readLine(line, 0, 128); newLine = new String(line, 0, i); // add the prefix to the filename PrintWriter pw = null; if (realSavePath.length() > 0) { pw = new PrintWriter(new BufferedWriter(new FileWriter((realSavePath == null ? "" : realSavePath) + filename))); } else { filename = filenamePrefix + filename; pw = new PrintWriter(new BufferedWriter(new FileWriter((savePath == null ? "" : savePath) + filename))); } while (i != -1 && !newLine.startsWith(boundary)) { // the problem is the last line of the file content // contains the new line character. // So, we need to check if the current line is // the last line. i = in.readLine(line, 0, 128); if ((i == boundaryLength + 2 || i == boundaryLength + 4) // + // 4 // is // eof && (new String(line, 0, i).startsWith(boundary))) { pw.print(newLine.substring(0, newLine.length() - 2)); } else { pw.print(newLine); } newLine = new String(line, 0, i); } pw.close(); } } } i = in.readLine(line, 0, 128); } // end while // if (realSavePath.length() > 0) { // LOGGER.info("User Configuration file received and saved at: " // + realSavePath + filename); // } else { // LOGGER.info("User Configuration file received and saved at: " // + savePath + filename); // } } private void handleUpload(ServletInputStream in, String type, String newLine) throws Exception { if (type.equals("javaProcess")) { // then parse classname String classname = newLine; String[] classnameArr = classname.replace(".", ",").split(","); String classdir = new String(); for (int c = 0; c < classnameArr.length - 1; c++) { if (c == 0) { classdir = classdir + classnameArr[c]; } else { classdir = classdir + File.separator + classnameArr[c]; } } realSavePath = new File(savePath).getParentFile() + "/WEB-INF/classes/"; realSavePath = realSavePath + classdir + File.separator; new File(realSavePath).mkdirs(); while (i != -1) { newLine = new String(line, 0, i); System.out.println(newLine); if (newLine.startsWith("Content-Disposition: form-data; name=\"")) { if (newLine.contains("processFile")) { // we upload files not config docuements. Therefore // store is // somewhere else. // realSavePath = new // File(savePath).getParentFile().getAbsolutePath()+"/WEB-INF/classes/"; /** * TODO: dir structure according to fully qual classname */ if (newLine.indexOf("filename=\"") != -1) { setFilename(new String(line, 0, i - 2)); if (filename == null) { return; } // this is the file content i = in.readLine(line, 0, 128); // next line i = in.readLine(line, 0, 128); // blank line i = in.readLine(line, 0, 128); newLine = new String(line, 0, i); // add the prefix to the filename PrintWriter pw = null; if (realSavePath.length() > 0) { pw = new PrintWriter(new BufferedWriter(new FileWriter((realSavePath == null ? "" : realSavePath) + filename))); } else { filename = filenamePrefix + filename; pw = new PrintWriter(new BufferedWriter(new FileWriter((savePath == null ? "" : savePath) + filename))); } while (i != -1 && !newLine.startsWith(boundary)) { // the problem is the last line of the file // content // contains the new line character. // So, we need to check if the current line is // the last line. i = in.readLine(line, 0, 128); if ((i == boundaryLength + 2 || i == boundaryLength + 4) // + // 4 // is // eof && (new String(line, 0, i).startsWith(boundary))) { pw.print(newLine.substring(0, newLine.length() - 2)); } else { pw.print(newLine); } newLine = new String(line, 0, i); } pw.close(); } } } i = in.readLine(line, 0, 128); } // end while if (realSavePath.length() > 0) { LOGGER.info("User Configuration file received and saved at: " + realSavePath + filename); } else { LOGGER.info("User Configuration file received and saved at: " + savePath + filename); } if (realSavePath.length() > 0) { compile(realSavePath + filename); } } else if (type.equals("rScript")) { // if processName the filename is used as ID, otherwise the script will be // renamed because r process IDs are derived from the filenames String processName = newLine.trim(); /* * FIXME This is very dirty. Changed from staticly referencing the * 52n-wps-r module (!!) to generic string property resolving. * Nevertheless, this is sort of hard-coded. The webadmin module * should be completely separated from others. */ String scriptDir = ""; Property[] rConfig = WPSConfig.getInstance().getPropertiesForRepositoryClass("org.n52.wps.server.r.LocalRAlgorithmRepository"); for (Property property : rConfig) { if (property.getName().equalsIgnoreCase("R_scriptDirectory")) { scriptDir = property.getStringValue(); } } File basedir = new File(savePath).getParentFile(); realSavePath = new File(basedir, scriptDir).getAbsolutePath()+File.separator; new File(realSavePath).mkdirs(); while (i != -1) { newLine = new String(line, 0, i); System.out.println(newLine); if (newLine.startsWith("Content-Disposition: form-data; name=\"")) { if (newLine.contains("rProcessFile")) { if (newLine.indexOf("filename=\"") != -1) { // filename is either the process name or the // original file name if (processName != null && !processName.isEmpty()) { filename = processName + ".R"; } else setFilename(new String(line, 0, i - 2)); if (filename == null) { return; } // this is the file content i = in.readLine(line, 0, 128); // next line i = in.readLine(line, 0, 128); // blank line i = in.readLine(line, 0, 128); newLine = new String(line, 0, i); // add the prefix to the filename PrintWriter pw = null; File destFile = null; if (realSavePath.length() > 0) { destFile = new File((realSavePath == null ? "" : realSavePath) + filename); pw = new PrintWriter(new BufferedWriter(new FileWriter(destFile))); } else { filename = filenamePrefix + filename; destFile = new File((savePath == null ? "" : savePath) + filename); pw = new PrintWriter(new BufferedWriter(new FileWriter(destFile))); } while (i != -1 && !newLine.startsWith(boundary)) { // the problem is the last line of the file // content // contains the new line character. // So, we need to check if the current line is // the last line. i = in.readLine(line, 0, 128); if ((i == boundaryLength + 2 || i == boundaryLength + 4) // + // 4 // is // eof && (new String(line, 0, i).startsWith(boundary))) { pw.print(newLine.substring(0, newLine.length() - 2)); } else { pw.print(newLine); } newLine = new String(line, 0, i); } pw.close(); } /* * FIXME This is very dirty. The webadmin module should * be completely separated from others. This one points * out the need for a generic * "reload your configuration" convenience method. * Changed to java Reflections to remove the static * 52n-wps-r module reference (though, very hardcoded). */ { LOGGER.info("R script uploaded, call to RPropertyChangeManager"); Class<?> clazz = Class.forName("org.n52.wps.server.r.RPropertyChangeManager"); Method method = clazz.getMethod("getInstance", null); Object instance = method.invoke(null, null); Method method2 = instance.getClass().getMethod("updateRepositoryConfiguration", null); method2.invoke(instance, null); // RPropertyChangeManager rmanager = // RPropertyChangeManager.getInstance(); // LOGGER.info("R script uploaded, call to RPropertyChangeManager"); // rmanager.addUnregisteredScripts(); } } } i = in.readLine(line, 0, 128); } // end while if (realSavePath.length() > 0) { LOGGER.info("User Configuration file received and saved at: " + realSavePath + filename); } else { LOGGER.info("User Configuration file received and saved at: " + savePath + filename); } if (realSavePath.length() > 0) { } } } public void compile(String fileName) { ClassLoader cl = this.getClass().getClassLoader(); List<URL> classpath = new ArrayList<URL>(); if (cl instanceof URLClassLoader) { URLClassLoader cl2 = (URLClassLoader) cl; for (URL jar : cl2.getURLs()) { classpath.add(jar); } } String classPath = System.getProperty("java.class.path"); for (String path : classPath.split(File.pathSeparator)) { try { classpath.add(new URL("file:" + path)); } catch (MalformedURLException e) { System.err.println("Wrong url: " + e.getMessage()); e.printStackTrace(); } } StringBuffer sb = new StringBuffer(); for (URL jar : classpath) { if (SystemUtils.IS_OS_WINDOWS == false) { sb.append(jar.getPath()); sb.append(File.pathSeparatorChar); } else { sb.append(jar.getPath().substring(1)); sb.append(File.pathSeparatorChar); } } String ops[] = new String[] { "-classpath", sb.toString() }; List<String> opsIter = new ArrayList<String>(); try { for (String s : ops) { // XXX test usage, removed use of deprecated method // ((ArrayList) opsIter).add(URLDecoder.decode(s)); ((ArrayList) opsIter).add(URLDecoder.decode(s, Charset.forName("UTF-8").toString())); } } catch (UnsupportedEncodingException e) { LOGGER.warn(e.getMessage(), e); } File[] files1 = new File[1]; files1[0] = new File(fileName); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); Iterable<? extends JavaFileObject> compilationUnits1 = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(files1)); compiler.getTask(null, fileManager, null, opsIter, null, compilationUnits1).call(); try { fileManager.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }