Initial Comit

This commit is contained in:
2021-12-19 10:56:25 +01:00
commit b8c9c75cf8
2351 changed files with 1819654 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
B4J=true
Group=Filters
ModulesStructureVersion=1
Type=Class
Version=9.1
@EndOfDesignText@
' Cross-Origin Resource Sharing (CORS) Filter class
Sub Class_Globals
Private cPath As String
Private cSettings As Map
End Sub
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize (Path As String, Settings As Map)
cPath = Path
cSettings = Settings
End Sub
'Return True to allow the request to proceed.
'Public Sub Filter (req As ServletRequest, resp As ServletResponse) As Boolean
' Return True
'End Sub
Public Sub AddToServer (ServerObject As Server)
Dim joServerWrapper As JavaObject = ServerObject
Dim joMe As JavaObject = Me
joMe.RunMethod("addFilter", Array As Object(joServerWrapper.GetField("context"), cPath, cSettings))
End Sub
#If JAVA
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map.Entry;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import anywheresoftware.b4a.objects.collections.Map.MyMap;
public void addFilter(ServletContextHandler context, String path, MyMap settings) throws Exception {
FilterHolder fh = new FilterHolder((Class<? extends Filter>) Class.forName("org.eclipse.jetty.servlets.CrossOriginFilter"));
if (settings != null) {
HashMap<String,String> m = new HashMap<String, String>();
copyMyMap(settings, m, true); //integerNumbersOnly!
fh.setInitParameters(m);
}
context.addFilter(fh, path, EnumSet.of(DispatcherType.REQUEST));
}
private void copyMyMap(MyMap m, java.util.Map<String, String> o, boolean integerNumbersOnly) {
for (Entry<Object, Object> e : m.entrySet()) {
String value;
if (integerNumbersOnly && e.getValue() instanceof Number) {
value = String.valueOf(((Number)e.getValue()).longValue());
} else {
value = String.valueOf(e.getValue());
o.put(String.valueOf(e.getKey()), value);
}
}
}
#End If

View File

@@ -0,0 +1,120 @@
B4J=true
Group=Modules
ModulesStructureVersion=1
Type=StaticCode
Version=9.1
@EndOfDesignText@
' DataUtils Code module
' Version 1.08
Sub Process_Globals
Dim pool As ConnectionPool
End Sub
Public Sub CreateDatabaseIfNotExist
Try
Dim DBFound As Boolean
Dim strSQL As String
Dim DBName As String = Main.Conn.DbName.As(String)
' SQLite
If Main.Conn.DbType.EqualsIgnoreCase("sqlite") Then
Log("Checking database...")
If File.Exists(File.DirApp, DBName) Then
Log("Database found!")
'DB.InitializeSQLite(File.DirApp, DBName, False)
Else
Log("Database not found!")
Log("Creating database...")
Dim DB As SQL
DB.InitializeSQLite(File.DirApp, DBName, True)
DB.ExecNonQuery("PRAGMA journal_mode = wal")
strSQL = Main.queries.Get("CREATE_TABLE_TBL_CATEGORY")
If strSQL <> "" Then DB.AddNonQueryToBatch(strSQL, Null)
strSQL = Main.queries.Get("INSERT_DUMMY_TBL_CATEGORY")
If strSQL <> "" Then DB.AddNonQueryToBatch(strSQL, Null)
strSQL = Main.queries.Get("CREATE_TABLE_TBL_PRODUCTS")
If strSQL <> "" Then DB.AddNonQueryToBatch(strSQL, Null)
strSQL = Main.queries.Get("INSERT_DUMMY_TBL_PRODUCTS")
If strSQL <> "" Then DB.AddNonQueryToBatch(strSQL, Null)
Dim SenderFilter As Object = DB.ExecNonQueryBatch("SQL")
Wait For (SenderFilter) SQL_NonQueryComplete (Success As Boolean)
If Success Then
Log("Database is created successfully!")
Else
Log("Database creation failed!")
End If
End If
End If
' MySQL
If Main.Conn.DbType.EqualsIgnoreCase("mysql") Then
Main.Conn.JdbcUrl = Main.Conn.JdbcUrl.Replace(DBName, "information_schema")
Dim con As SQL = OpenDB
If con.IsInitialized Then
Log($"Checking database..."$)
strSQL = Main.queries.Get("CHECK_DATABASE")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As String(DBName))
Do While res.NextRow
DBFound = True
Loop
res.Close
If DBFound Then
Log("Database found!")
Else
Log("Database not found!")
Log("Creating database...")
strSQL = Main.queries.Get("CREATE_DATABASE").As(String).Replace("{DBNAME}", DBName) ' Can't use prepared statement
If strSQL <> "" Then con.AddNonQueryToBatch(strSQL, Null)
strSQL = Main.queries.Get("USE_DATABASE").As(String).Replace("{DBNAME}", DBName)
If strSQL <> "" Then con.AddNonQueryToBatch(strSQL, Null)
'strSQL = Main.queries.Get("DROP_TABLE_IF_EXIST_TBL_CATEGORY")
'If strSQL <> "" Then con.AddNonQueryToBatch(strSQL, Null)
strSQL = Main.queries.Get("CREATE_TABLE_TBL_CATEGORY")
If strSQL <> "" Then con.AddNonQueryToBatch(strSQL, Null)
strSQL = Main.queries.Get("INSERT_DUMMY_TBL_CATEGORY")
If strSQL <> "" Then con.AddNonQueryToBatch(strSQL, Null)
'strSQL = Main.queries.Get("DROP_TABLE_IF_EXIST_TBL_PRODUCTS")
'If strSQL <> "" Then con.AddNonQueryToBatch(strSQL, Null)
strSQL = Main.queries.Get("CREATE_TABLE_TBL_PRODUCTS")
If strSQL <> "" Then con.AddNonQueryToBatch(strSQL, Null)
strSQL = Main.queries.Get("INSERT_DUMMY_TBL_PRODUCTS")
If strSQL <> "" Then con.AddNonQueryToBatch(strSQL, Null)
Dim SenderFilter As Object = con.ExecNonQueryBatch("SQL")
Wait For (SenderFilter) SQL_NonQueryComplete (Success As Boolean)
If Success Then
Log("Database is created successfully!")
Else
Log("Database creation failed!")
End If
End If
End If
End If
Catch
LogError(LastException)
CloseDB(con)
Log("Error creating database!")
Log("Application is terminated.")
ExitApplication
End Try
CloseDB(con)
' Revert jdbcUrl to normal
Main.Conn.JdbcUrl = Main.config.Get("JdbcUrl")
End Sub
Sub OpenDB As SQL
If Main.Conn.DbType.EqualsIgnoreCase("mysql") Then
pool = Main.OpenConnection(pool)
Return pool.GetConnection
End If
Return Null
End Sub
Sub CloseDB (con As SQL)
If con <> Null And con.IsInitialized Then con.Close
If Main.Conn.DbType.EqualsIgnoreCase("mysql") Then
If pool.IsInitialized Then pool.ClosePool
End If
End Sub

View File

@@ -0,0 +1,18 @@
B4J=true
Group=Default Group
ModulesStructureVersion=1
Type=Class
Version=9.1
@EndOfDesignText@
'Handler class
Sub Class_Globals
End Sub
Public Sub Initialize
End Sub
Sub Handle(req As ServletRequest, resp As ServletResponse)
End Sub

View File

@@ -0,0 +1,154 @@
<div class="content m-3">
<div class="p-2">
<div class="row">
<div class="col">
<h3>$HOME_TITLE$</h3>
<span class="small">Version: $VERSION$</span>
<div class="small">Local time: <span id="datetime"></span>
<script type="text/javascript">
var datetime = document.getElementById('datetime');
var d = new Date();
var formatted = d.getFullYear() + '-' +
('0' + (d.getMonth()+1)).slice(-2) + '-' +
('0' + d.getDate()).slice(-2) + ' ' +
('0' + d.getHours()).slice(-2) + ':' +
('0' + d.getMinutes()).slice(-2) + ':' +
('0' + d.getSeconds()).slice(-2);
datetime.innerHTML = formatted;
</script>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-md-12">
<h3 class="text-uppercase text-primary"><span class='fa fa-layer-group mr-1'></span> <strong>Category</strong></h3>
</div>
</div>
<div class="row mt-3">
<div class="col-md-12">
<div class="table-responsive">
<table class="table table-bordered rounded table-light small">
<thead class="bg-secondary text-white">
<th class="col-md-5 h6"><strong>Description</strong></th>
<th class="col-md-1 h6 text-center"><strong>Method</strong></th>
<th class="col-md-3 h6"><strong>Payload</strong></th>
<th class="col-md-3 h6"><strong>API Endpoint</strong></th>
</thead>
<tbody>
<tr>
<td>List all categories</td>
<td class="text-center text-success">GET</td>
<td></td>
<td><a href="$ROOT_URL$$ROOT_PATH$category" target="_blank">/category</a></td>
</tr>
<tr>
<td>Get a category by id</td>
<td class="text-center text-success">GET</td>
<td></td>
<td><a href="$ROOT_URL$$ROOT_PATH$category/2" target="_blank">/category/{cat_id}</a></td>
</tr>
<tr>
<td>Add a new category</td>
<td class="text-center text-warning">POST</td>
<td>{<br>
&nbsp; "name": "category_name"<br>
}</td>
<td>/category</td>
</tr>
<tr>
<td>Update existing category by id</td>
<td class="text-center text-primary">PUT</td>
<td>{<br>
&nbsp; "name": "category_name"<br>
}</td>
<td>/category/{cat_id}</td>
</tr>
<tr>
<td>Delete existing category by id</td>
<td class="text-center text-danger">DELETE</td>
<td></td>
<td>/category/{cat_id}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-md-12">
<h3 class="text-uppercase text-primary"><span class='fa fa-cart-arrow-down mr-1'></span> <strong>Product</strong></h3>
</div>
</div>
<div class="row mt-3">
<div class="col-md-12">
<div class="table-responsive">
<table class="table table-bordered rounded table-light small">
<thead class="bg-secondary text-white">
<th class="col-md-5 h6"><strong>Description</strong></th>
<th class="col-md-1 h6 text-center"><strong>Method</strong></th>
<th class="col-md-3 h6"><strong>Payload</strong></th>
<th class="col-md-3 h6"><strong>API Endpoint</strong></th>
</thead>
<tbody>
<tr>
<td>List all products by category id</td>
<td class="text-center text-success">GET</td>
<td></td>
<td><a href="$ROOT_URL$$ROOT_PATH$category/2/product" target="_blank">/category/{cat_id}/product</a></td>
</tr>
<tr>
<td>Get a product by category and id</td>
<td class="text-center text-success">GET</td>
<td></td>
<td><a href="$ROOT_URL$$ROOT_PATH$category/2/product/3" target="_blank">/category/{cat_id}/product/{id}</a></td>
</tr>
<tr>
<td>Add a new product by category id</td>
<td class="text-center text-warning">POST</td>
<td>{<br>
&nbsp; "code": "product_code",<br>
&nbsp; "name": "product_name",<br>
&nbsp; "price": product_price<br>
}</td>
<td>/category/{cat_id}/product</td>
</tr>
<tr>
<td>Update existing product by category id and id</td>
<td class="text-center text-primary">PUT</td>
<td>{<br>
&nbsp; "code": "product_code",<br>
&nbsp; "name": "product_name",<br>
&nbsp; "price": product_price<br>
}</td>
<td>/category/{cat_id}/product/{id}</td>
</tr>
<tr>
<td>Delete existing product by category id and id</td>
<td class="text-center text-danger">DELETE</td>
<td></td>
<td>/category/{cat_id}/product/{id}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-md-12">
<form class="form mb-3" action="">
<div class="input-group input-group-sm">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroup-sizing-sm">Keywords</span>
</div>
<input class="form-control col-md-3" type="text" id="keywords" name="keywords">
<button class="btn btn-danger btn-sm pl-3 pr-3 ml-3" type="hidden" id="btnsearch">Search</button>
</div>
</form>
<div id="results" class="table">
<table class="table table-bordered rounded small">
</table>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,30 @@
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>$APP_TITLE$</title>
<link rel="icon" type="image/png" href="$ROOT_URL$/assets/img/favicon.png"/>
<link rel="stylesheet" href="$ROOT_URL$/assets/css/bootstrap.min.css">
<link rel="stylesheet" href="$ROOT_URL$/assets/css/fontawesome.min.css">
<link rel="stylesheet" href="$ROOT_URL$/assets/css/solid.min.css">
<style type="text/css">
body {
font-family: Arial, Helvetica, Tahoma, Times New Roman;
}
</style>
</head>
<body class="bg-light">
<nav class="navbar navbar-expand navbar-dark bg-primary">
<a class="text-white mr-3" href="#"><i class="fas fa-rocket"></i></a>
<a class="navbar-brand font-weight-bold" href="$ROOT_URL$$ROOT_PATH$">$APP_TRADEMARK$</a>
</nav>
@VIEW@
<div class="footer small m-4"><caption>$APP_COPYRIGHT$</caption></div>
<script src="$ROOT_URL$/assets/js/jquery.min.js"></script>
<script src="$ROOT_URL$/assets/js/bootstrap.bundle.min.js"></script>
<script src="$ROOT_URL$/assets/js/webapisearch.js"></script>
</body>
</html>

View File

@@ -0,0 +1,101 @@
B4J=true
Group=Handlers
ModulesStructureVersion=1
Type=Class
Version=8.1
@EndOfDesignText@
' Home Handler class
Sub Class_Globals
Dim Request As ServletRequest
Dim Response As ServletResponse
Dim pool As ConnectionPool
End Sub
Public Sub Initialize
End Sub
Sub Handle(req As ServletRequest, resp As ServletResponse)
Request = req
Response = resp
' Search e.g. ' http://127.0.0.1:19800/v1/?search=ha
If Request.GetParameter("search") <> "" Then ' GET
Search(Request.GetParameter("search"))
Else if Request.Method.ToUpperCase = "POST" Then
Dim keywords As String = req.GetParameter("keywords").Trim
Search(keywords)
Else
ShowHomePage
End If
End Sub
Private Sub ShowHomePage
Dim strMain As String = Utility.ReadTextFile("main.html")
Dim strView As String = Utility.ReadTextFile("index.html")
strMain = Utility.BuildView(strMain, strView)
strMain = Utility.BuildHtml(strMain, Main.config)
Utility.ReturnHTML(strMain, Response)
End Sub
Sub Search (SearchForText As String)
Dim con As SQL = OpenDB
Dim strSQL As String
Try
Dim keys() As String = Regex.Split2(" ", 2, SearchForText)
If keys.Length < 2 Then
Dim s1 As String = SearchForText.Trim
'Log(s1)
strSQL = Main.queries.Get("SEARCH_PRODUCT_BY_CATEGORY_CODE_AND_NAME_ONEWORD_ORDERED")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As String("%" & s1 & "%", "%" & s1 & "%", "%" & s1 & "%"))
Else
Dim s1 As String = keys(0).Trim
Dim s2 As String = SearchForText.Replace(keys(0), "").Trim
'Log(s1 & "," & s2)
strSQL = Main.queries.Get("SEARCH_PRODUCT_BY_CATEGORY_CODE_AND_NAME_TWOWORDS_ORDERED")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As String("%" & s1 & "%", "%" & s1 & "%", "%" & s1 & "%", _
"%" & s2 & "%", "%" & s2 & "%", "%" & s2 & "%"))
End If
Dim List1 As List
List1.Initialize
Do While res.NextRow
Dim Map2 As Map
Map2.Initialize
For i = 0 To res.ColumnCount - 1
If res.GetColumnName(i) = "aa" Then
Map2.Put(res.GetColumnName(i), res.GetInt2(i))
Else If res.GetColumnName(i) = "ee" Then
Map2.Put(res.GetColumnName(i), NumberFormat2(res.GetDouble2(i), 1, 2, 2, True))
Else
Map2.Put(res.GetColumnName(i), res.GetString2(i))
End If
Next
List1.Add(Map2)
Loop
Utility.ReturnSuccess2(List1, 200, Response)
Catch
LogDebug(LastException)
Utility.ReturnError("Error Execute Query", 422, Response)
End Try
CloseDB(con)
End Sub
Sub OpenDB As SQL
If Main.Conn.DbType.EqualsIgnoreCase("mysql") Then
pool = Main.OpenConnection(pool)
Return pool.GetConnection
End If
If Main.Conn.DbType.EqualsIgnoreCase("sqlite") Then
Return Main.OpenSQLiteDB
End If
Return Null
End Sub
Sub CloseDB (con As SQL)
If con <> Null And con.IsInitialized Then con.Close
If Main.Conn.DbType.EqualsIgnoreCase("mysql") Then
If pool.IsInitialized Then pool.ClosePool
End If
End Sub

View File

@@ -0,0 +1,25 @@
B4J=true
Group=Filters
ModulesStructureVersion=1
Type=Class
Version=8.5
@EndOfDesignText@
' Https Filter class
Sub Class_Globals
End Sub
Public Sub Initialize
End Sub
'Return True to allow the request to proceed.
Public Sub Filter (req As ServletRequest, resp As ServletResponse) As Boolean
If req.Secure Then
Return True
Else
resp.SendRedirect(req.FullRequestURI.Replace("http:", "https:") _
.Replace(Main.srvr.Port, Main.srvr.SslPort))
Return False
End If
End Sub

View File

@@ -0,0 +1,196 @@
AppType=StandardJava
Build1=Default,b4j.webapi
File1=index.html
File2=main.html
FileGroup1=Default Group
FileGroup2=Default Group
Group=Default Group
Library1=byteconverter
Library2=jcore
Library3=jserver
Library4=json
Library5=jsql
Library6=javaobject
Module1=CorsFilter
Module2=DataUtils
Module3=DefaultHandler
Module4=HomeHandler
Module5=HttpsFilter
Module6=ProductHandler
Module7=Utility
Module8=WebUtils
NumberOfFiles=2
NumberOfLibraries=6
NumberOfModules=8
Version=9.1
@EndOfDesignText@
' Name: Web API Lite
' Description: Non-UI application (console / server application)
' Version: 1.08
#Region Project Attributes
#CommandLineArgs:
#MergeLibraries: True
#End Region
#Region AdditionalJar
' MySQL connector
'#AdditionalJar: mysql-connector-java-5.1.49-bin
' SQLite connector
#AdditionalJar: sqlite-jdbc-3.36.0.2
#End Region
Sub Process_Globals
Public const VERSION As Float = 1.08
Public srvr As Server
Public ROOT_PATH As String
Public ROOT_URL As String
Public SERVER_PORT As Int
Public SSL_PORT As Int
Public config As Map
Public queries As Map
Public Conn As Conn
Public Element As Element
Type Conn (DbName As String, DbType As String, DriverClass As String, JdbcUrl As String, User As String, Password As String, MaxPoolSize As Int)
Type Element (Root As Int, Parent As Int, Parent_Id As Int, Child As Int, Child_Id As Int, Max_Elements As Int)
End Sub
Sub AppStart (Args() As String)
config = Utility.ReadMapFile(File.DirApp, "config.ini")
If config.Get("DbType").As(String).EqualsIgnoreCase("mysql") Then
queries = Utility.ReadMapFile(File.DirApp, "queries-mysql.ini")
End If
If config.Get("DbType").As(String).EqualsIgnoreCase("sqlite") Then
queries = Utility.ReadMapFile(File.DirApp, "queries-sqlite.ini")
End If
ROOT_PATH = config.Get("ROOT_PATH")
ROOT_URL = config.Get("ROOT_URL")
SERVER_PORT = config.Get("ServerPort")
SSL_PORT = config.Get("SSLPort") : If IsNumber(SSL_PORT) = False Then SSL_PORT = 0
If SERVER_PORT = 0 Then
Log($"Server Port is not set!"$)
Log($"Application is terminated."$)
ExitApplication
End If
ROOT_URL = ROOT_URL & ":" & SERVER_PORT
srvr.Initialize("")
srvr.Port = SERVER_PORT
If SSL_PORT > 0 Then
ConfigureSSL(SSL_PORT)
ROOT_URL = config.Get("ROOT_URL") & ":" & SSL_PORT
End If
' Update ROOT URL
config.Put("ROOT_URL", ROOT_URL)
config.Put("VERSION", VERSION)
Conn.Initialize
Conn.DbName = config.Get("DbName")
Conn.DbType = config.Get("DbType")
Conn.DriverClass = config.Get("DriverClass")
Conn.JdbcUrl = config.Get("JdbcUrl")
If Conn.DbType.EqualsIgnoreCase("mysql") Then
Conn.User = config.Get("User")
Conn.Password = config.Get("Password")
Conn.MaxPoolSize = config.Get("MaxPoolSize")
End If
' Check if database exists
DataUtils.CreateDatabaseIfNotExist
Element.Initialize
If ROOT_PATH <> "/" Then ' If webroot is using subdirectory
srvr.AddHandler(ROOT_PATH, "HomeHandler", False)
Element.Root = 1
Element.Parent = 2
Element.Parent_Id = 3
Element.Child = 4
Element.Child_Id = 5
Element.Max_Elements = 6
Else
Element.Root = 0
Element.Parent = 1
Element.Parent_Id = 2
Element.Child = 3
Element.Child_Id = 4
Element.Max_Elements = 5
End If
srvr.StaticFilesFolder = File.Combine(File.DirApp, "www")
srvr.SetStaticFilesOptions(CreateMap("dirAllowed": False))
' Add a home page
srvr.AddHandler("", "HomeHandler", False)
' Add more handlers here
srvr.AddHandler(ROOT_PATH & "default/*", "DefaultHandler", False)
srvr.AddHandler(ROOT_PATH & "category/*", "ProductHandler", False)
' Add CrossOriginFilter
'ConfigureCORS("/*", "*", "*", "*")
'ConfigureCORS(ROOT_PATH & "category/*", "http://127.0.0.1:19800", "", "") ' test.html
ConfigureCORS(ROOT_PATH & "category/*", "*", "", "")
' Server starts
srvr.Start
Log($"Web API server (version = $1.2{VERSION}) is running on port ${srvr.Port}"$)
Log($"Open the following URL from your web browser"$)
Log(ROOT_URL & ROOT_PATH)
' Open a web browser and navigate to: http://127.0.0.1:19800/v1/
StartMessageLoop
End Sub
Public Sub OpenConnection (pool As ConnectionPool) As ConnectionPool
Try
pool.Initialize(Conn.DriverClass, Conn.JdbcUrl, Conn.User, Conn.Password)
Dim jo As JavaObject = pool
jo.RunMethod("setMaxPoolSize", Array(Conn.MaxPoolSize))
Catch
LogDebug(LastException)
End Try
Return pool
End Sub
Public Sub OpenSQLiteDB As SQL
Dim DB As SQL
DB.InitializeSQLite(File.DirApp, Conn.DbName, False)
Return DB
End Sub
#Region ConfigureSSL
Private Sub ConfigureSSL (SslPort As Int)
Dim KeyStoreDir As String = config.Get("SSL_KEYSTORE_DIR")
Dim KeyStoreFile As String = config.Get("SSL_KEYSTORE_FILE")
Dim KeyStorePassword As String = config.Get("SSL_KEYSTORE_PASSWORD")
Dim ssl As SslConfiguration
ssl.Initialize
ssl.SetKeyStorePath(KeyStoreDir, KeyStoreFile)
ssl.KeyStorePassword = KeyStorePassword
'ssl.KeyManagerPassword = ""
srvr.SetSslConfiguration(ssl, SslPort)
'add filter to redirect all traffic from http to https (optional)
srvr.AddFilter("/*", "HttpsFilter", False)
End Sub
#End Region
#Region ConfigureCORS
' allowedOrigins = "*" or "http://google.com"
' allowedMethods = "*" or "GET,POST,HEAD"
' allowedHeaders = "*" or "X-Requested-With,Content-Type,Accept,Origin"
Private Sub ConfigureCORS (Path As String, allowedOrigins As String, allowedMethods As String, allowedHeaders As String)
' Reference: https://www.b4x.com/android/forum/threads/jetty-cross-origin-filter-to-be-added-to-jserver-library.85641/
Dim cors As CorsFilter
cors.Initialize(Path, CreateMap("allowedOrigins": allowedOrigins, _
"allowedMethods": allowedMethods, _
"allowedHeaders": allowedHeaders, _
"allowCredentials": "true", _
"preflightMaxAge": 1800, _
"chainPreflight": "false"))
cors.AddToServer(srvr)
End Sub
#End Region

View File

@@ -0,0 +1,43 @@
# Product: Web API (server)
# Version: 1.08
# Developer: Aeric Poon
# License: Open Source
# Thanks to Erel, Anywhere Software for the great products and B4X community for encouragement and supports ;)
# Lines starting with '#' are comments.
# Backslash character at the end of line means that the command continues in the next line.
# Server Path
ROOT_PATH=/v1/
ROOT_URL=http://127.0.0.1
# Java server port
ServerPort=19800
SSLPort=0
# SSL Keystores
SSL_KEYSTORE_DIR=/etc/letsencrypt/live/mydomain.com
SSL_KEYSTORE_FILE=keystore.jks
SSL_KEYSTORE_PASSWORD=xxxxxx
# Define App Constants
HOME_TITLE=WEB API
APP_TITLE=Web API
APP_TRADEMARK=B4X
APP_COPYRIGHT=Copyright B4X 2021
# DATABASE CONFIGURATION
# SQLite
DbName=webapi.db
DbType=sqlite
DriverClass=com.sqlite.JdbcUrl
JdbcUrl=jdbc:sqlite:webapi.db
# MySQL
# DbName=webapi
# DbType=mysql
# DriverClass=com.mysql.jdbc.Driver
# JdbcUrl=jdbc:mysql://localhost/webapi?characterEncoding=utf8&useSSL=false
# User=root
# Password=password
# MaxPoolSize=100

View File

@@ -0,0 +1,78 @@
# Product: SQL commands for Web API (for MySQL Backend)
# Version: 1.08
# Lines starting with '#' are comments.
# Backslash character at the end of line means that the command continues in the next line.
# Check and create database
CHECK_DATABASE=SELECT * FROM SCHEMATA WHERE SCHEMA_NAME = ?
CREATE_DATABASE=CREATE DATABASE {DBNAME} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
USE_DATABASE=USE {DBNAME}
# DROP_TABLE_IF_EXIST_TBL_CATEGORY=DROP TABLE IF EXISTS `tbl_category`
CREATE_TABLE_TBL_CATEGORY=CREATE TABLE `tbl_category` ( \
`id` int(11) NOT NULL AUTO_INCREMENT, \
`category_name` varchar(200) COLLATE utf8mb4_unicode_ci DEFAULT NULL, \
PRIMARY KEY (`id`) \
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
INSERT_DUMMY_TBL_CATEGORY=INSERT INTO `tbl_category` (`category_name`) VALUES \
('Hardwares'), \
('Toys')
# DROP_TABLE_IF_EXIST_TBL_PRODUCTS=DROP TABLE IF EXISTS `tbl_products`
CREATE_TABLE_TBL_PRODUCTS=CREATE TABLE `tbl_products` ( \
`id` int(11) NOT NULL AUTO_INCREMENT, \
`category_id` int(11) NOT NULL, \
`product_code` varchar(12) COLLATE utf8mb4_unicode_ci DEFAULT NULL, \
`product_name` varchar(200) COLLATE utf8mb4_unicode_ci DEFAULT NULL, \
`product_price` decimal(10,2) DEFAULT '0.00', \
PRIMARY KEY (`id`), \
KEY `category_id` (`category_id`), \
CONSTRAINT `tbl_products_ibfk_1` FOREIGN KEY (`category_id`) REFERENCES `tbl_category` (`id`) \
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
INSERT_DUMMY_TBL_PRODUCTS=INSERT INTO `tbl_products` \
(`category_id`, `product_code`, `product_name`, `product_price`) VALUES \
(2, 'T001', 'Teddy Bear', 99.9), \
(1, 'H001', 'Hammer', 15.75), \
(2, 'T002', 'Optimus Prime', 1000.00)
# CATEGORY
GET_ALL_CATEGORIES=SELECT * FROM `tbl_category`
GET_CATEGORY_BY_ID=SELECT * FROM `tbl_category` WHERE `id` = ?
ADD_NEW_CATEGORY=INSERT INTO `tbl_category` (`category_name`) SELECT ?
EDIT_CATEGORY_BY_ID=UPDATE `tbl_category` SET `category_name` = ? WHERE `id` = ?
REMOVE_CATEGORY_BY_ID=DELETE FROM `tbl_category` WHERE `id` = ?
GET_ID_BY_CATEGORY_NAME=SELECT `id` FROM `tbl_category` WHERE `category_name` = ?
# PRODUCT
GET_ALL_PRODUCTS_BY_CATEGORY=SELECT * FROM `tbl_products` \
WHERE `category_id` = ?
GET_PRODUCT_BY_CATEGORY_AND_ID=SELECT * FROM `tbl_products` \
WHERE `category_id` = ? AND `id` = ?
ADD_NEW_PRODUCT_BY_CATEGORY=INSERT INTO `tbl_products` \
(`category_id`, `product_code`, `product_name`, `product_price`) SELECT ?, ?, ?, ?
EDIT_PRODUCT_BY_CATEGORY_AND_ID=UPDATE `tbl_products` \
SET `category_id` = ?, `product_code` = ?, `product_name` = ?, `product_price` = ? \
WHERE `category_id` = ? AND `id` = ?
REMOVE_PRODUCT_BY_CATEGORY_AND_ID=DELETE FROM `tbl_products` \
WHERE `category_id` = ? AND `id` = ?
GET_ID_BY_CATEGORY_ID_AND_PRODUCT_NAME=SELECT `id` FROM `tbl_products` \
WHERE `category_id` = ? AND `product_name` = ?
# SEARCH
SEARCH_PRODUCT_BY_CATEGORY_CODE_AND_NAME_ONEWORD_ORDERED=SELECT P.id AS aa, \
P.product_code AS bb, C.`category_name` AS cc, P.product_name AS dd, P.product_price AS ee \
FROM `tbl_products` P JOIN `tbl_category` C ON P.`category_id` = C.`id` \
WHERE C.`category_name` LIKE ? OR P.`product_code` LIKE ? OR P.`product_name` LIKE ?
SEARCH_PRODUCT_BY_CATEGORY_CODE_AND_NAME_TWOWORDS_ORDERED=SELECT P.id AS aa, \
P.product_code AS bb, C.`category_name` AS cc, P.product_name AS dd, P.product_price AS ee \
FROM `tbl_products` P JOIN `tbl_category` C ON P.`category_id` = C.`id` \
WHERE C.`category_name` LIKE ? OR P.`product_code` LIKE ? OR P.`product_name` LIKE ? \
OR C.`category_name` LIKE ? OR P.`product_code` LIKE ? OR P.`product_name` LIKE ?
GET_LAST_INSERT_ID=SELECT LAST_INSERT_ID()

View File

@@ -0,0 +1,65 @@
# Product: SQL commands for Web API (for SQLite Backend)
# Version: 1.08
# Lines starting with '#' are comments.
# Backslash character at the end of line means that the command continues in the next line.
# Create tables
CREATE_TABLE_TBL_CATEGORY=CREATE TABLE IF NOT EXISTS `tbl_category` ( \
`id` INTEGER PRIMARY KEY AUTOINCREMENT, \
`category_name` varchar(200) NULL \
)
INSERT_DUMMY_TBL_CATEGORY=INSERT INTO `tbl_category` (`category_name`) VALUES \
('Hardwares'), \
('Toys')
CREATE_TABLE_TBL_PRODUCTS=CREATE TABLE IF NOT EXISTS `tbl_products` ( \
`id` INTEGER PRIMARY KEY AUTOINCREMENT, \
`category_id` INTEGER NOT NULL, \
`product_code` varchar(12) NULL, \
`product_name` varchar(200) NULL, \
`product_price` decimal(10,2) DEFAULT '0.00', \
FOREIGN KEY (`category_id`) REFERENCES `tbl_category` (`id`) \
)
INSERT_DUMMY_TBL_PRODUCTS=INSERT INTO `tbl_products` \
(`category_id`, `product_code`, `product_name`, `product_price`) VALUES \
(2, 'T001', 'Teddy Bear', 99.9), \
(1, 'H001', 'Hammer', 15.75), \
(2, 'T002', 'Optimus Prime', 1000.00)
# CATEGORY
GET_ALL_CATEGORIES=SELECT * FROM `tbl_category`
GET_CATEGORY_BY_ID=SELECT * FROM `tbl_category` WHERE `id` = ?
ADD_NEW_CATEGORY=INSERT INTO `tbl_category` (`category_name`) SELECT ?
EDIT_CATEGORY_BY_ID=UPDATE `tbl_category` SET `category_name` = ? WHERE `id` = ?
REMOVE_CATEGORY_BY_ID=DELETE FROM `tbl_category` WHERE `id` = ?
GET_ID_BY_CATEGORY_NAME=SELECT `id` FROM `tbl_category` WHERE `category_name` = ?
# PRODUCT
GET_ALL_PRODUCTS_BY_CATEGORY=SELECT * FROM `tbl_products` \
WHERE `category_id` = ?
GET_PRODUCT_BY_CATEGORY_AND_ID=SELECT * FROM `tbl_products` \
WHERE `category_id` = ? AND `id` = ?
ADD_NEW_PRODUCT_BY_CATEGORY=INSERT INTO `tbl_products` \
(`category_id`, `product_code`, `product_name`, `product_price`) SELECT ?, ?, ?, ?
EDIT_PRODUCT_BY_CATEGORY_AND_ID=UPDATE `tbl_products` \
SET `category_id` = ?, `product_code` = ?, `product_name` = ?, `product_price` = ? \
WHERE `category_id` = ? AND `id` = ?
REMOVE_PRODUCT_BY_CATEGORY_AND_ID=DELETE FROM `tbl_products` \
WHERE `category_id` = ? AND `id` = ?
GET_ID_BY_CATEGORY_ID_AND_PRODUCT_NAME=SELECT `id` FROM `tbl_products` \
WHERE `category_id` = ? AND `product_name` = ?
# SEARCH
SEARCH_PRODUCT_BY_CATEGORY_CODE_AND_NAME_ONEWORD_ORDERED=SELECT P.id AS aa, \
P.product_code AS bb, C.`category_name` AS cc, P.product_name AS dd, P.product_price AS ee \
FROM `tbl_products` P JOIN `tbl_category` C ON P.`category_id` = C.`id` \
WHERE C.`category_name` LIKE ? OR P.`product_code` LIKE ? OR P.`product_name` LIKE ?
SEARCH_PRODUCT_BY_CATEGORY_CODE_AND_NAME_TWOWORDS_ORDERED=SELECT P.id AS aa, \
P.product_code AS bb, C.`category_name` AS cc, P.product_name AS dd, P.product_price AS ee \
FROM `tbl_products` P JOIN `tbl_category` C ON P.`category_id` = C.`id` \
WHERE C.`category_name` LIKE ? OR P.`product_code` LIKE ? OR P.`product_name` LIKE ? \
OR C.`category_name` LIKE ? OR P.`product_code` LIKE ? OR P.`product_name` LIKE ?
GET_LAST_INSERT_ID=SELECT LAST_INSERT_ROWID()

View File

@@ -0,0 +1,14 @@
REM ================================================================
REM Run this batch file in Windows Command Prompt as Administrator
REM ================================================================
@ECHO OFF
TITLE Web API server is starting...
REM CD C:\Java\jdk-11.0.1\bin
REM java --module-path C:\Java\jdk-11.0.1\javafx\lib --add-modules ALL-MODULE-PATH -jar "C:\Development\B4J\WebAPI\Objects\webapi.jar"
C:
CD C:\Program Files\Java\jdk1.8.0_181\bin
java -jar "C:\Development\B4J\WebAPI\Objects\webapi.jar"
::PAUSE

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
/*!
* Font Awesome Free 5.8.1 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/
@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Free";font-weight:900}

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,50 @@
$( document ).ready(function() {
$("#btnsearch").click(function(e) {
e.preventDefault();
$.ajax({
type: "POST",
url: "/",
data: $("form").serialize(),
success: function(response)
{
if (response.s == "ok") {
// console.log(response.r);
var tbl_head = "";
var tbl_body = "";
if (response.r.length) {
tbl_head = "<thead class=\"bg-light\"><th style=\"text-align: right\">#</th><th>Code</th><th>Category</th><th>Name</th><th style=\"text-align: right\">Price</th></thead>";
tbl_body += "<tbody>";
$.each(response.r, function() {
var tbl_row = "";
$.each(this, function(key, value) {
if (key == "ee" || key == "aa")
{
tbl_row += "<td style=\"text-align: right\">"+value+"</td>";
}
else
{
tbl_row += "<td>"+value+"</td>";
}
});
tbl_body += "<tr>"+tbl_row+"</tr>";
});
tbl_body += "</tbody>";
}
else
{
tbl_body = "<tr><td>No results</td></tr>";
}
$("#results table").html(tbl_head+tbl_body);
}
else {
$(".alert").html(response.e);
$(".alert").fadeIn();
}
},
error: function (xhr, ajaxOptions, thrownError) {
$(".alert").html(thrownError);
$(".alert").fadeIn();
}
});
});
});

View File

@@ -0,0 +1,403 @@
B4J=true
Group=Handlers
ModulesStructureVersion=1
Type=Class
Version=9.1
@EndOfDesignText@
' Product Handler class
Sub Class_Globals
Dim Request As ServletRequest
Dim Response As ServletResponse
Dim pool As ConnectionPool
Dim Elements() As String
End Sub
Public Sub Initialize
End Sub
Sub Handle (req As ServletRequest, resp As ServletResponse)
Request = req
Response = resp
Elements = Regex.Split("/", req.RequestURI)
If CheckMaxElements = False Then
Utility.ReturnError("Bad Request", 400, Response)
Return
End If
If CheckAllowedVerb = False Then
Utility.ReturnError("Method Not Allowed", 405, Response)
Return
End If
ProcessRequest
End Sub
Private Sub ProcessRequest
Select Case Request.Method.ToUpperCase
Case "GET"
Select Case Elements.Length - 1
Case Main.Element.Root ' /
Case Main.Element.Parent ' /category
If Elements(Main.Element.Parent) = "category" Then
GetCategories("")
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Case Main.Element.Parent_Id ' /category/{cat_id}
If Elements(Main.Element.Parent) = "category" Then
GetCategories(Elements(Main.Element.Parent_Id))
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Case Main.Element.Child ' /category/{cat_id}/product
If Elements(Main.Element.Parent) = "category" And Elements(Main.Element.Child) = "product" Then
GetProductsByCategories(Elements(Main.Element.Parent_Id), "")
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Case Main.Element.Child_Id ' /category/{cat_id}/product/{product_id}
If Elements(Main.Element.Parent) = "category" And Elements(Main.Element.Child) = "product" Then
GetProductsByCategories(Elements(Main.Element.Parent_Id), Elements(Main.Element.Child_Id))
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Case Else
Utility.ReturnError("Bad Request", 400, Response)
End Select
Case "POST"
Select Case Elements.Length - 1
Case Main.Element.Parent ' /category
If Elements(Main.Element.Parent) = "category" Then
PostCategory
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Case Main.Element.Child ' /category/{cat_id}/product
If Elements(Main.Element.Parent) = "category" And Elements(Main.Element.Child) = "product" Then
PostProductByCategory(Elements(Main.Element.Parent_Id))
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Case Else
Utility.ReturnError("Bad Request", 400, Response)
End Select
Case "PUT"
Select Case Elements.Length - 1
Case Main.Element.Parent_Id ' /category/{cat_id}
If Elements(Main.Element.Parent) = "category" Then
PutCategoryById(Elements(Main.Element.Parent_Id))
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Case Main.Element.Child_Id ' /category/{cat_id}/product/{product_id}
If Elements(Main.Element.Parent) = "category" And Elements(Main.Element.Child) = "product" Then
PutProductByCategoryAndId(Elements(Main.Element.Parent_Id), Elements(Main.Element.Child_Id))
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Case Else
Utility.ReturnError("Bad Request", 400, Response)
End Select
Case "DELETE"
Select Case Elements.Length - 1
Case Main.Element.Parent_Id ' /category/{cat_id}
If Elements(Main.Element.Parent) = "category" Then
DeleteCategoryById(Elements(Main.Element.PARENT_ID))
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Case Main.Element.Child_Id ' /category/{cat_id}/product/{product_id}
If Elements(Main.Element.Parent) = "category" And Elements(Main.Element.Child) = "product" Then
DeleteProductsByCategoryAndId(Elements(Main.Element.Parent_Id), Elements(Main.Element.Child_Id))
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Case Else
Utility.ReturnError("Bad Request", 400, Response)
End Select
End Select
End Sub
Private Sub CheckMaxElements As Boolean
If Elements.Length > Main.Element.Max_Elements Or Elements.Length = 0 Then
Return False
End If
Return True
End Sub
Private Sub CheckAllowedVerb As Boolean
'Methods: POST, GET, PUT, PATCH, DELETE
Dim SupportedMethods As List = Array As String("POST", "GET", "PUT", "DELETE")
If SupportedMethods.IndexOf(Request.Method) = -1 Then
Return False
End If
Return True
End Sub
Sub OpenDB As SQL
If Main.Conn.DbType.EqualsIgnoreCase("mysql") Then
pool = Main.OpenConnection(pool)
Return pool.GetConnection
End If
If Main.Conn.DbType.EqualsIgnoreCase("sqlite") Then
Return Main.OpenSQLiteDB
End If
Return Null
End Sub
Sub CloseDB (con As SQL)
If con <> Null And con.IsInitialized Then con.Close
If Main.Conn.DbType.EqualsIgnoreCase("mysql") Then
If pool.IsInitialized Then pool.ClosePool
End If
End Sub
Sub GetCategories (cat_id As String)
Dim con As SQL = OpenDB
Dim strSQL As String
Try
If cat_id = "" Then
strSQL = Main.queries.Get("GET_ALL_CATEGORIES")
Dim res As ResultSet = con.ExecQuery(strSQL)
Else
strSQL = Main.queries.Get("GET_CATEGORY_BY_ID")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As String(cat_id))
End If
Dim List1 As List
List1.Initialize
Do While res.NextRow
Dim Map2 As Map
Map2.Initialize
For i = 0 To res.ColumnCount - 1
Map2.Put(res.GetColumnName(i), res.GetString2(i))
Next
List1.Add(Map2)
Loop
If List1.Size = 0 Then
Utility.ReturnError("Category Not Found", 404, Response)
Else
Utility.ReturnSuccess2(List1, 200, Response)
End If
Catch
LogDebug(LastException)
Utility.ReturnError("Error Execute Query", 422, Response)
End Try
CloseDB(con)
End Sub
Sub GetProductsByCategories (cat_id As String, id As String)
Dim con As SQL = OpenDB
Dim strSQL As String
Try
If id = "" Then
strSQL = Main.queries.Get("GET_ALL_PRODUCTS_BY_CATEGORY")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As String(cat_id))
Else
strSQL = Main.queries.Get("GET_PRODUCT_BY_CATEGORY_AND_ID")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As String(cat_id, id))
End If
Dim List1 As List
List1.Initialize
Do While res.NextRow
Dim Map2 As Map
Map2.Initialize
For i = 0 To res.ColumnCount - 1
If res.GetColumnName(i) = "product_price" Then
Map2.Put(res.GetColumnName(i), res.GetDouble2(i))
Else If res.GetColumnName(i) = "category_id" Or res.GetColumnName(i) = "id" Then
Map2.Put(res.GetColumnName(i), res.GetInt2(i))
Else
Map2.Put(res.GetColumnName(i), res.GetString2(i))
End If
Next
List1.Add(Map2)
Loop
If List1.Size = 0 Then
Utility.ReturnError("Product Not Found", 404, Response)
Else
Utility.ReturnSuccess2(List1, 200, Response)
End If
Catch
LogDebug(LastException)
Utility.ReturnError("Error Execute Query", 422, Response)
End Try
CloseDB(con)
End Sub
Sub PostCategory
Dim con As SQL = OpenDB
Dim strSQL As String
Try
Dim data As Map = Utility.RequestData(Request)
If data.IsInitialized Then
strSQL = Main.queries.Get("GET_ID_BY_CATEGORY_NAME")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As String(data.Get("name")))
If res.NextRow Then
Utility.ReturnError("Category Already Exist", 409, Response)
Else
strSQL = Main.queries.Get("ADD_NEW_CATEGORY")
con.BeginTransaction
con.ExecNonQuery2(strSQL, Array As String(data.Get("name")))
strSQL = Main.queries.Get("GET_LAST_INSERT_ID")
Dim NewId As Int = con.ExecQuerySingleResult(strSQL)
strSQL = Main.queries.Get("GET_CATEGORY_BY_ID")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As String(NewId))
con.TransactionSuccessful
Dim List1 As List
List1.Initialize
Do While res.NextRow
Dim Map2 As Map
Map2.Initialize
For i = 0 To res.ColumnCount - 1
Map2.Put(res.GetColumnName(i), res.GetString2(i))
Next
List1.Add(Map2)
Loop
Utility.ReturnSuccess2(List1, 201, Response)
'Dim URL As String = $"${Main.ROOT_URL}${Main.ROOT_PATH}category/${NewId}"$
'Utility.ReturnLocation(URL, 201, Response)
End If
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Catch
LogDebug(LastException)
Utility.ReturnError("Error Execute Query", 422, Response)
End Try
CloseDB(con)
End Sub
Sub PostProductByCategory (cat_id As String)
Dim con As SQL = OpenDB
Dim strSQL As String
Try
strSQL = Main.queries.Get("GET_CATEGORY_BY_ID")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As String(cat_id))
If res.NextRow Then
Dim data As Map = Utility.RequestData(Request)
If data.IsInitialized Then
strSQL = Main.queries.Get("ADD_NEW_PRODUCT_BY_CATEGORY")
con.BeginTransaction
con.ExecNonQuery2(strSQL, Array As String(cat_id, data.Get("code"), data.Get("name"), data.Get("price")))
strSQL = Main.queries.Get("GET_LAST_INSERT_ID")
Dim NewId As Int = con.ExecQuerySingleResult(strSQL)
strSQL = Main.queries.Get("GET_PRODUCT_BY_CATEGORY_AND_ID")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As String(cat_id, NewId))
con.TransactionSuccessful
Dim List1 As List
List1.Initialize
Do While res.NextRow
Dim Map2 As Map
Map2.Initialize
For i = 0 To res.ColumnCount - 1
Map2.Put(res.GetColumnName(i), res.GetString2(i))
Next
List1.Add(Map2)
Loop
Utility.ReturnSuccess2(List1, 201, Response)
'Dim URL As String = $"${Main.ROOT_URL}${Main.ROOT_PATH}category/${cat_id}/${NewId}"$
'Utility.Returnlocation(URL, 201, Response)
Return
End If
Else
Utility.ReturnError("Category Not Found", 404, Response)
End If
Catch
LogDebug(LastException)
Utility.ReturnError("Error Execute Query", 422, Response)
End Try
CloseDB(con)
End Sub
Sub PutCategoryById (cat_id As String)
Dim con As SQL = OpenDB
Dim strSQL As String
Try
strSQL = Main.queries.Get("GET_CATEGORY_BY_ID")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As String(cat_id))
If res.NextRow Then
Dim data As Map = Utility.RequestData(Request)
If data.IsInitialized Then
strSQL = Main.queries.Get("EDIT_CATEGORY_BY_ID")
con.ExecNonQuery2(strSQL, Array As Object(data.Get("name"), cat_id))
Utility.ReturnSuccess(CreateMap("result": "success"), 200, Response)
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Else
Utility.ReturnError("Category Not Found", 404, Response)
End If
Catch
LogDebug(LastException)
Utility.ReturnError("Error Execute Query", 422, Response)
End Try
CloseDB(con)
End Sub
Sub PutProductByCategoryAndId (cat_id As String, id As String)
Dim con As SQL = OpenDB
Dim strSQL As String
Try
strSQL = Main.queries.Get("GET_PRODUCT_BY_CATEGORY_AND_ID")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As String(cat_id, id))
If res.NextRow Then
Dim data As Map = Utility.RequestData(Request)
If data.IsInitialized Then
strSQL = Main.queries.Get("EDIT_PRODUCT_BY_CATEGORY_AND_ID")
con.ExecNonQuery2(strSQL, Array As Object(cat_id, data.Get("code"), data.Get("name"), data.Get("price"), cat_id, id))
Utility.ReturnSuccess(CreateMap("result": "success"), 200, Response)
Else
Utility.ReturnError("Bad Request", 400, Response)
End If
Else
Utility.ReturnError("Product Not Found", 404, Response)
End If
Catch
LogDebug(LastException)
Utility.ReturnError("Error Execute Query", 422, Response)
End Try
CloseDB(con)
End Sub
Sub DeleteCategoryById (cat_id As String)
Dim con As SQL = OpenDB
Dim strSQL As String
Try
strSQL = Main.queries.Get("GET_CATEGORY_BY_ID")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As Int(cat_id))
If res.NextRow Then
strSQL = Main.queries.Get("REMOVE_CATEGORY_BY_ID")
con.ExecNonQuery2(strSQL, Array As Int(cat_id))
Utility.ReturnSuccess(CreateMap("result": "success"), 200, Response)
Else
Utility.ReturnError("Category Not Found", 404, Response)
End If
Catch
LogDebug(LastException)
Utility.ReturnError("Error Execute Query", 422, Response)
End Try
CloseDB(con)
End Sub
Sub DeleteProductsByCategoryAndId (cat_id As String, id As String)
Dim con As SQL = OpenDB
Dim strSQL As String
Try
strSQL = Main.queries.Get("GET_PRODUCT_BY_CATEGORY_AND_ID")
Dim res As ResultSet = con.ExecQuery2(strSQL, Array As Int(cat_id, id))
If res.NextRow Then
strSQL = Main.queries.Get("REMOVE_PRODUCT_BY_CATEGORY_AND_ID")
con.ExecNonQuery2(strSQL, Array As Int(cat_id, id))
Utility.ReturnSuccess(CreateMap("result": "success"), 200, Response)
Else
Utility.ReturnError("Product Not Found", 404, Response)
End If
Catch
LogDebug(LastException)
Utility.ReturnError("Error Execute Query", 422, Response)
End Try
CloseDB(con)
End Sub

View File

@@ -0,0 +1,102 @@
B4J=true
Group=Modules
ModulesStructureVersion=1
Type=StaticCode
Version=8.1
@EndOfDesignText@
' Utility Code module
' Version 1.08
Sub Process_Globals
Private const CONTENT_TYPE_JSON As String = "application/json"
Private const CONTENT_TYPE_HTML As String = "text/html"
End Sub
Public Sub BuildHtml (strHTML As String, Settings As Map) As String
' Replace $KEY$ tag with new content from Map
strHTML = WebUtils.ReplaceMap(strHTML, Settings)
Return strHTML
End Sub
Public Sub BuildView (strHTML As String, View As String) As String
' Replace @VIEW@ tag with new content
strHTML = strHTML.Replace("@VIEW@", View)
Return strHTML
End Sub
Public Sub ReadMapFile (FileDir As String, FileName As String) As Map
Dim strPath As String = File.Combine(FileDir, FileName)
Log($"Reading file (${strPath})..."$)
Return File.ReadMap(FileDir, FileName)
End Sub
Public Sub ReadTextFile (FileName As String) As String
Return File.ReadString(File.DirAssets, FileName)
End Sub
Public Sub Map2Json (M As Map) As String
Return M.As(JSON).ToString
End Sub
public Sub RequestData (Request As ServletRequest) As Map
Dim mdl As String = "RequestData"
Try
Dim data As Map
Dim ins As InputStream = Request.InputStream
If ins.BytesAvailable <= 0 Then
Return data
End If
Dim tr As TextReader
tr.Initialize(ins)
Dim json As JSONParser
json.Initialize(tr.ReadAll)
data = json.NextObject
Catch
LogDebug($"${mdl} "$ & LastException)
End Try
Return data
End Sub
Public Sub ReturnHTML (str As String, resp As ServletResponse)
resp.ContentType = CONTENT_TYPE_HTML
resp.Write(str)
End Sub
Public Sub ReturnConnect (resp As ServletResponse)
Dim Result As List
Result.Initialize
Result.Add(CreateMap("connect": "true"))
resp.ContentType = CONTENT_TYPE_JSON
resp.Write(Map2Json(CreateMap("s": "ok", "m": "success", "r": Result, "e": Null)))
End Sub
Public Sub ReturnError (Error As String, Code As Int, resp As ServletResponse)
If Error = "" Then Error = "unknown"
Dim Result As List
Result.Initialize
resp.ContentType = CONTENT_TYPE_JSON
resp.Status = Code
resp.Write(Map2Json(CreateMap("s": "error", "m": Null, "r": Result, "e": Error)))
End Sub
Public Sub ReturnSuccess (Data As Map, Code As Int, resp As ServletResponse)
If Data.IsInitialized = False Then Data.Initialize
Dim Result As List
Result.Initialize
Result.Add(Data)
Dim Map1 As Map = CreateMap("s": "ok", "m": "success", "r": Result, "e": Null)
resp.ContentType = CONTENT_TYPE_JSON
resp.Status = Code
resp.Write(Map2Json(Map1))
End Sub
Public Sub ReturnSuccess2 (Data As List, Code As Int, resp As ServletResponse)
If Data.IsInitialized = False Then Data.Initialize
Dim Map1 As Map = CreateMap("s": "ok", "m": "success", "r": Data, "e": Null)
resp.ContentType = CONTENT_TYPE_JSON
resp.Status = Code
resp.Write(Map2Json(Map1))
End Sub
Public Sub ReturnLocation (Location As String, resp As ServletResponse) ' Code = 302
resp.SendRedirect(Location)
End Sub

View File

@@ -0,0 +1,91 @@
B4J=true
Group=Modules
ModulesStructureVersion=1
Type=StaticCode
Version=8.31
@EndOfDesignText@
' WebUtils Code module
' Version 1.00
Sub Process_Globals
Public bc As ByteConverter
End Sub
Public Sub init
bc.LittleEndian = True
End Sub
#Region Test
Public Sub EscapeHtml(Raw As String) As String
Dim sb As StringBuilder
sb.Initialize
For i = 0 To Raw.Length - 1
Dim C As Char = Raw.CharAt(i)
Select C
Case QUOTE
sb.Append("&quot;")
Case "'"
sb.Append("&#39;")
Case "<"
sb.Append("&lt;")
Case ">"
sb.Append("&gt;")
Case "&"
sb.Append("&amp;")
Case Else
sb.Append(C)
End Select
Next
Return sb.ToString
End Sub
Public Sub ReplaceMap(Base As String, Replacements As Map) As String
Dim pattern As StringBuilder
pattern.Initialize
For Each k As String In Replacements.Keys
If pattern.Length > 0 Then pattern.Append("|")
pattern.Append("\$").Append(k).Append("\$")
Next
Dim m As Matcher = Regex.Matcher(pattern.ToString, Base)
Dim result As StringBuilder
result.Initialize
Dim lastIndex As Int
Do While m.Find
result.Append(Base.SubString2(lastIndex, m.GetStart(0)))
Dim replace As String = Replacements.Get(m.Match.SubString2(1, m.Match.Length - 1))
If m.Match.ToLowerCase.StartsWith("$h_") Then replace = EscapeHtml(replace)
result.Append(replace)
lastIndex = m.GetEnd(0)
Loop
If lastIndex < Base.Length Then result.Append(Base.SubString(lastIndex))
Return result.ToString
End Sub
Public Sub RedirectTo(ws As WebSocket, TargetUrl As String)
ws.Eval("window.location = arguments[0]", Array As Object(TargetUrl))
End Sub
Public Sub ReadString(In As InputStream) As String
Dim len As Int = bc.IntsFromBytes(ReadBytesFromStream(In, 4))(0)
Return BytesToString(ReadBytesFromStream(In, len), 0, len, "UTF8")
End Sub
#End Region
Sub ReadBytesFromStream(In As InputStream, Length As Int) As Byte()
If Length > 5000 Then
Log("Error reading from stream")
Return Null
End If
Dim b(Length) As Byte
Dim count As Int = 0
Do While count < Length
Dim read As Int = In.ReadBytes(b, count, Length - count)
If read <= 0 Then
Log("Error reading from stream.")
Return Null
End If
count = count + read
Loop
Return b
End Sub