JavaXT
|
|
Server Classpackage javaxt.express; import javaxt.express.cms.Content; import javaxt.http.servlet.HttpServlet; import javaxt.http.servlet.HttpServletRequest; import javaxt.http.servlet.HttpServletResponse; import javaxt.http.servlet.ServletException; import javaxt.sql.*; import javaxt.json.*; import javaxt.io.Jar; import static javaxt.utils.Console.*; import java.util.*; import java.io.IOException; import javaxt.express.utils.DbUtils; //****************************************************************************** //** Express Server //****************************************************************************** /** * Command line application used to start a web server and serve content. * ******************************************************************************/ public class Server { //************************************************************************** //** main //************************************************************************** /** Command line interface used to start the server. * @param arguments Command line arguments */ public static void main(String[] arguments) throws Exception { HashMap<String, String> args = parseArgs(arguments); Jar jar = new Jar(Server.class); //Process command line args if (args.containsKey("-version")){ String version = jar.getVersion(); if (version==null) version = "Unknown"; System.out.println(version); } else if (args.containsKey("-deploy")){ Deploy.main(arguments); } else if (args.containsKey("-start")){ javaxt.utils.Value start = getValue(args, "-start"); Config config = getConfig(args, jar); try { //Get servlet HttpServlet servlet; if (start.equals("website") || start.equals("cms")){ servlet = new WebSite(config, args); } else if (start.equals("webservice") || start.equals("webservices")){ servlet = new WebServices(config, args); } else{ servlet = new WebServer(config, args); } //Start server int port = config.get("webserver").get("port").toInteger(); int numThreads = config.get("webserver").get("numThreads").toInteger(); javaxt.http.Server server = new javaxt.http.Server(port, numThreads, servlet); server.start(); } catch (Exception e) { System.out.println("Server could not start because of an " + e.getClass() + ": " + e.getMessage()); e.printStackTrace(); } } else{ System.out.println("Unsupported command"); } } //************************************************************************** //** WebSite //************************************************************************** /** Returns an HTTP servlet used serve content using the Express Content * Management System (CMS). */ private static class WebSite extends javaxt.express.cms.WebSite { private WebSite(Config config, HashMap<String, String> args){ super(getDirectory(config)); } private static javaxt.io.Directory getDirectory(Config config){ javaxt.io.Directory web = null; try{ web = (javaxt.io.Directory) config.get("webserver").get("webDir").toObject(); } catch(Exception e){} if (web==null) throw new IllegalArgumentException( "Invalid directory. Use the -dir argument to specify a path to a CMS folder."); return web; } /* Override the native getContent method to generate custom HTML for wiki * pages. Performs custom keyword substitution for the "<%=index%>" tag. */ public Content getContent(HttpServletRequest request, javaxt.io.File file){ //Get path from url String path = request.getURL().getPath().toLowerCase(); //Remove leading and trailing "/" characters if (path.startsWith("/")) path = path.substring(1); if (path.endsWith("/")) path = path.substring(0, path.length()-1); //Return content if (path.equals("wiki")){ String html = file.getText(); Date date = file.getDate(); if (file.getName(false).equals("index")){ Content content = getIndex(file); javaxt.utils.Date d = new javaxt.utils.Date(content.getDate()); if (d.isAfter(new javaxt.utils.Date(date))){ date = d.getDate(); } html = html.replace("<%=index%>", content.getHTML()); } return new Content(html, date); } else{ return super.getContent(request, file); } } } //************************************************************************** //** WebServer //************************************************************************** /** Returns an HTTP servlet used serve static files using the FileManager. * The FileManager ensures that files are properly cached by the browser. */ private static class WebServer extends HttpServlet { private FileManager fileManager; public WebServer(Config config, HashMap<String, String> args){ //Get directory javaxt.io.Directory web = null; try{ web = (javaxt.io.Directory) config.get("webserver").get("webDir").toObject(); } catch(Exception e){} if (web==null) throw new IllegalArgumentException( "Invalid directory. Use the -dir argument to specify a path to a web folder."); //If we're still here, instantiate the file manager fileManager = new FileManager(web); } public void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { fileManager.sendFile(request, response); } } //************************************************************************** //** WebServices //************************************************************************** /** Returns an HTTP servlet used execute CRUD operations (create, read, * update, delete) using a given set of models. */ private static class WebServices extends HttpServlet { private WebService ws; private Database database; public WebServices(Config config, HashMap<String, String> args) throws Exception { //Parse inputs String input = getValue(args, "-model", "-models").toString(); javaxt.io.File inputFile; try { inputFile = new javaxt.io.File(input); if (!inputFile.exists()) throw new Exception(); } catch(Exception e){ throw new IllegalArgumentException("Models are required"); } database = config.getDatabase(); if (database==null) throw new IllegalArgumentException("Invalid or missing database"); //Get models javaxt.orm.Model[] models = new javaxt.orm.Parser(inputFile.getText()).getModels(); //Initialize schema (create tables, indexes, etc) String schema = new javaxt.orm.Schema(models).getSQLScript(); if (database.getDriver().equals("H2")){ //Set H2 to PostgreSQL mode Properties properties = database.getProperties(); if (properties==null){ properties = new java.util.Properties(); database.setProperties(properties); } properties.setProperty("MODE", "PostgreSQL"); properties.setProperty("DATABASE_TO_LOWER", "TRUE"); properties.setProperty("DEFAULT_NULL_ORDERING", "HIGH"); //Update list of non-reserved keywords (e.g. "KEY", "VALUE", "YEAR") HashSet<String> nonKeyWords = new HashSet<>(); Set<String> resevedKeyWords = new HashSet<>( Arrays.asList(database.getReservedKeywords()) ); for (javaxt.orm.Model model : models){ String str = model.getTableName().toUpperCase(); if (resevedKeyWords.contains(str)) nonKeyWords.add(str); for (javaxt.orm.Field field : model.getFields()){ str = field.getColumnName().toUpperCase(); if (resevedKeyWords.contains(str)) nonKeyWords.add(str); } } if (!nonKeyWords.isEmpty()){ properties.setProperty("NON_KEYWORDS", String.join(",", nonKeyWords)); } } DbUtils.initSchema(database, schema, null); //Enable metadata caching database.enableMetadataCache(true); //Inititalize connection pool database.initConnectionPool(); //Compile models into classes Class[] classes = new javaxt.orm.Compiler(models).getClasses(); //Instantiate web services ws = new Demo(); //Initialize classes and register them with the web service for (Class c : classes){ Model.init(c, database.getConnectionPool()); ws.addModel(c); } } public void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //Add CORS support response.addHeader("Access-Control-Allow-Origin", "*"); response.addHeader("Access-Control-Allow-Headers","*"); response.addHeader("Access-Control-Allow-Methods", "*"); ServiceRequest req = new ServiceRequest(request); ServiceResponse rsp = ws.getServiceResponse(req, database); rsp.send(response); } private class Demo extends WebService {} } //************************************************************************** //** getConfig //************************************************************************** private static Config getConfig(HashMap<String, String> args, Jar jar){ javaxt.io.File jarFile = new javaxt.io.File(jar.getFile()); //Get config file javaxt.io.File configFile = (args.containsKey("-config")) ? getFile(args.get("-config"), jarFile) : new javaxt.io.File(jar.getFile().getParentFile(), "config.json"); //Initialize config Config config = new Config(); if (configFile.exists()){ try{ config.init(configFile.getJSONObject()); } catch(Exception e){} } //Get web config JSONObject webConfig = config.get("webserver").toJSONObject(); if (webConfig==null){ webConfig = new JSONObject(); config.set("webserver", webConfig); } //Set directory for the web server try{ String dir = getValue(args, "-d", "-dir", "-directory", "-web", "-share").toString(); if (dir.endsWith("\"")) dir = dir.substring(0, dir.length()-1); java.io.File f = new java.io.File(dir); if (f.isFile()) f = f.getParentFile(); javaxt.io.Directory web = new javaxt.io.Directory(f); webConfig.set("webDir", web); } catch(Exception e){} //Set port for the web server Integer port = getValue(args, "-p", "-port").toInteger(); if (port==null && !webConfig.has("port")) webConfig.set("port", 8080); else webConfig.set("port", port); //Set number of threads for the web server Integer numThreads = getValue(args, "-t", "-threads").toInteger(); if (numThreads==null && !webConfig.has("numThreads")) webConfig.set("numThreads", 250); else webConfig.set("numThreads", numThreads); //Get database config Database database = config.getDatabase(); if (database==null){ String db = getValue(args, "-database", "-data").toString(); if (db!=null){ try{ //Check if the database arg represents a path to a directory String path = db; javaxt.io.Directory dir = new javaxt.io.Directory(path); if (dir.exists()){ try{ java.io.File f = new java.io.File(path); javaxt.io.Directory d = new javaxt.io.Directory(f.getCanonicalFile()); if (!dir.toString().equals(d.toString())){ dir = d; } } catch(Exception e){ } } else{ path = (configFile.exists()) ? configFile.MapPath(path) : jarFile.MapPath(path); dir = new javaxt.io.Directory(new java.io.File(path)); } //If the directory doesn't exist, throw an error. Do not try //to create a new directory because the path may be invalid. if (!dir.exists()) throw new Exception(); //Create a new database using H2 database = new Database(); database.setDriver("H2"); database.setHost(dir.toString().replace("\\", "/") + "database"); } catch(Exception e){ //Try parsing connection string if (args.containsKey("-database")){ try{ database = new Database(db); } catch(Exception ex){} } } //Update database config if (database!=null){ int maxConnections = Math.min(25, webConfig.get("numThreads").toInteger()); database.setConnectionPoolSize(maxConnections); config.setDatabase(database); } } } return config; } //************************************************************************** //** getFile //************************************************************************** /** Returns a File for a given path * @param path Full canonical path to a file or a relative path (relative * to the jarFile) */ public static javaxt.io.File getFile(String path, javaxt.io.File jarFile){ javaxt.io.File file = new javaxt.io.File(path); if (!file.exists()){ file = new javaxt.io.File(jarFile.MapPath(path)); } return file; } } |