Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
D
Distributed-Search-Engine
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tammam.alsoleman
Distributed-Search-Engine
Commits
a8f0b211
Commit
a8f0b211
authored
Jan 21, 2026
by
tammam.alsoleman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
create the FrontendApplication
parent
d1b92d05
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
146 additions
and
0 deletions
+146
-0
FrontendApplication.java
...main/java/com/distributed/search/FrontendApplication.java
+146
-0
No files found.
src/main/java/com/distributed/search/FrontendApplication.java
0 → 100644
View file @
a8f0b211
package
com
.
distributed
.
search
;
import
com.distributed.search.cluster.LeaderHttpRegistry
;
import
com.sun.net.httpserver.HttpExchange
;
import
com.sun.net.httpserver.HttpServer
;
import
org.apache.zookeeper.WatchedEvent
;
import
org.apache.zookeeper.Watcher
;
import
org.apache.zookeeper.ZooKeeper
;
import
java.io.IOException
;
import
java.io.OutputStream
;
import
java.net.InetSocketAddress
;
import
java.net.URI
;
import
java.net.URISyntaxException
;
import
java.net.http.HttpClient
;
import
java.net.http.HttpRequest
;
import
java.net.http.HttpResponse
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
java.util.concurrent.Executors
;
public
class
FrontendApplication
implements
Watcher
{
private
static
final
String
ZOOKEEPER_ADDRESS
=
"192.168.39.250:2181"
;
// Use your ZK IP
private
static
final
int
PORT
=
8080
;
// Main Web Port
private
final
LeaderHttpRegistry
leaderHttpRegistry
;
private
final
HttpClient
httpClient
;
public
FrontendApplication
(
ZooKeeper
zooKeeper
)
{
this
.
leaderHttpRegistry
=
new
LeaderHttpRegistry
(
zooKeeper
);
this
.
httpClient
=
HttpClient
.
newBuilder
().
build
();
}
public
static
void
main
(
String
[]
args
)
throws
Exception
{
ZooKeeper
zooKeeper
=
new
ZooKeeper
(
ZOOKEEPER_ADDRESS
,
3000
,
event
->
{});
FrontendApplication
app
=
new
FrontendApplication
(
zooKeeper
);
app
.
startServer
();
}
public
void
startServer
()
throws
IOException
{
HttpServer
server
=
HttpServer
.
create
(
new
InetSocketAddress
(
PORT
),
0
);
// Context 1: Serve the HTML UI
server
.
createContext
(
"/"
,
this
::
handleHomeRequest
);
// Context 2: API Proxy to Leader
server
.
createContext
(
"/api/search"
,
this
::
handleSearchApiRequest
);
server
.
setExecutor
(
Executors
.
newFixedThreadPool
(
8
));
server
.
start
();
System
.
out
.
println
(
"Frontend Server is running at http://localhost:"
+
PORT
);
}
// Serves the index.html file to the browser
private
void
handleHomeRequest
(
HttpExchange
exchange
)
throws
IOException
{
byte
[]
response
=
Files
.
readAllBytes
(
Paths
.
get
(
"src/main/resources/index.html"
));
exchange
.
getResponseHeaders
().
set
(
"Content-Type"
,
"text/html"
);
sendResponse
(
response
,
exchange
);
}
// Receives query from browser -> Finds Leader -> Fetches results from Leader -> Returns to browser
private
void
handleSearchApiRequest
(
HttpExchange
exchange
)
throws
IOException
{
// 1. Only support GET requests
if
(!
"GET"
.
equalsIgnoreCase
(
exchange
.
getRequestMethod
()))
{
exchange
.
sendResponseHeaders
(
405
,
-
1
);
return
;
}
// 2. Get the RAW query from browser (e.g., query=blue%20car)
String
query
=
exchange
.
getRequestURI
().
getRawQuery
();
String
leaderUrl
=
leaderHttpRegistry
.
getLeaderAddress
();
if
(
leaderUrl
==
null
)
{
sendPlainTextResponse
(
"Leader not found in registry"
,
exchange
,
502
);
return
;
}
try
{
// 3. Robust URL Construction
// Ensure leaderUrl has protocol and the correct endpoint
if
(!
leaderUrl
.
startsWith
(
"http"
))
leaderUrl
=
"http://"
+
leaderUrl
;
if
(!
leaderUrl
.
contains
(
"/search"
))
leaderUrl
=
leaderUrl
.
replaceAll
(
"/$"
,
""
)
+
"/search"
;
// Create the final URI carefully
// concatenation of (base) + (?) + (already encoded query)
URI
uri
=
URI
.
create
(
leaderUrl
+
"?"
+
query
);
System
.
out
.
println
(
"Frontend Proxying to Leader: "
+
uri
);
// 4. Prepare the HTTP Request to the Leader
HttpRequest
request
=
HttpRequest
.
newBuilder
()
.
uri
(
uri
)
.
GET
()
.
timeout
(
java
.
time
.
Duration
.
ofSeconds
(
30
))
.
build
();
// 5. Send request and get response as InputStream (Efficiency)
HttpResponse
<
java
.
io
.
InputStream
>
resp
=
httpClient
.
send
(
request
,
HttpResponse
.
BodyHandlers
.
ofInputStream
());
int
statusCode
=
resp
.
statusCode
();
exchange
.
getResponseHeaders
().
set
(
"Content-Type"
,
"application/json; charset=utf-8"
);
if
(
statusCode
!=
200
)
{
byte
[]
errorBytes
=
resp
.
body
().
readAllBytes
();
sendPlainTextResponse
(
new
String
(
errorBytes
),
exchange
,
statusCode
);
return
;
}
// 6. Stream the results directly from Leader to Browser
try
(
java
.
io
.
InputStream
is
=
resp
.
body
();
OutputStream
os
=
exchange
.
getResponseBody
())
{
// Send headers first (200 OK, 0 means chunked/unknown length)
exchange
.
sendResponseHeaders
(
200
,
0
);
is
.
transferTo
(
os
);
// Copy data directly
os
.
flush
();
}
}
catch
(
IllegalArgumentException
e
)
{
System
.
err
.
println
(
"Invalid Query format: "
+
e
.
getMessage
());
sendPlainTextResponse
(
"Invalid search format"
,
exchange
,
400
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
sendPlainTextResponse
(
"Error communicating with Leader: "
+
e
.
getMessage
(),
exchange
,
502
);
}
}
private
void
sendPlainTextResponse
(
String
text
,
HttpExchange
exchange
,
int
status
)
throws
IOException
{
byte
[]
bytes
=
text
.
getBytes
(
java
.
nio
.
charset
.
StandardCharsets
.
UTF_8
);
exchange
.
getResponseHeaders
().
set
(
"Content-Type"
,
"text/plain; charset=utf-8"
);
exchange
.
sendResponseHeaders
(
status
,
bytes
.
length
);
try
(
OutputStream
os
=
exchange
.
getResponseBody
())
{
os
.
write
(
bytes
);
}
}
private
void
sendResponse
(
byte
[]
bytes
,
HttpExchange
exchange
)
throws
IOException
{
exchange
.
sendResponseHeaders
(
200
,
bytes
.
length
);
try
(
OutputStream
os
=
exchange
.
getResponseBody
())
{
os
.
write
(
bytes
);
}
}
@Override
public
void
process
(
WatchedEvent
event
)
{}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment