Official Java SDK for Roomzin — a high-performance in-memory inventory engine for booking platforms.
The SDK provides a clean, idiomatic Java interface for communicating with Roomzin servers in both standalone and clustered deployments. It automatically manages routing, failover, connection pooling, and cluster topology changes.
- Automatic request routing (leader for writes, followers for reads)
- Built-in failover and cluster discovery
- Connection pooling
- Standalone and clustered deployment support
- Fully typed Java API
- AutoCloseable client for resource management
- Java 8 or later
- Roomzin Server v1.x
<dependency>
<groupId>io.github.m-javani</groupId>
<artifactId>roomzin-java</artifactId>
<version>1.0.0</version>
</dependency>implementation 'com.roomzin:roomzin-java:1.0.0'import com.roomzin.roomzinjava.single.SingleClient;
import com.roomzin.roomzinjava.api.CacheClientApi;
import java.time.Duration;
CacheClientApi client = SingleConfig.builder()
.withHost("127.0.0.1")
.withTcpPort(7777)
.withAuthToken("abc123")
.withTimeout(Duration.ofSeconds(5))
.withKeepAlive(Duration.ofSeconds(30))
.build();
// Use client...
client.close();import com.roomzin.roomzinjava.cluster.ClusterClient;
import com.roomzin.roomzinjava.cluster.ClusterConfig;
import com.roomzin.roomzinjava.types.NodeAddr;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
List<NodeAddr> staticDiscovery = Arrays.asList(
new NodeAddr("roomzin-0", "172.20.0.10", 7777, 8080),
new NodeAddr("roomzin-1", "172.20.0.11", 7777, 8080),
new NodeAddr("roomzin-2", "172.20.0.12", 7777, 8080)
);
ClusterConfig cfg = ClusterConfig.builder()
.withSeedNodeIds("roomzin-0, roomzin-1, roomzin-2")
.withStaticDiscovery(staticDiscovery)
.withTcpPort(7777)
.withApiPort(8080)
.withAuthToken("abc123")
.withTimeout(Duration.ofSeconds(5))
.withKeepAlive(Duration.ofSeconds(30))
.build();
CacheClientApi client = ClusterClient.create(cfg);
client.close();ClusterConfig cfg = ClusterConfig.builder()
.withSeedNodeIds("roomzin-0, roomzin-1, roomzin-2")
.withHttpDiscovery("http://discovery-service:8080/nodes")
.withTcpPort(7777)
.withApiPort(8080)
.withAuthToken("abc123")
.withTimeout(Duration.ofSeconds(5))
.withKeepAlive(Duration.ofSeconds(30))
.build();
CacheClientApi client = ClusterClient.create(cfg);Roomzin SDKs need to know how to reach each Roomzin node in the cluster. The cluster nodes communicate with each other using internal address resolvers, but the SDK as an external client needs actual network addresses (IP:port or hostname:port) to connect.
The SDK fetches the cluster topology from the Roomzin cluster itself. This topology includes the node identities of the leader and followers. The SDK then uses discovery to resolve these node identities into actual network addresses.
Two discovery modes are supported:
The SDK gets the mapping once in config and never updates it. Use this when your cluster nodes have stable, predictable addresses.
The SDK periodically fetches the mapping from an HTTP endpoint. Use this when cluster nodes are dynamic (e.g., Kubernetes pods with changing IPs).
Adds or updates a property.
client.setProp(SetPropPayload.builder()
.segment("downtown")
.area("manhattan")
.propertyId("hotel_123")
.propertyType("hotel")
.category("luxury")
.stars((short) 4)
.latitude(40.7128)
.longitude(-74.0060)
.amenities(Arrays.asList("wifi", "pool", "gym"))
.build());Searches properties by segment, area, type, or location.
// By segment
List<String> ids = client.searchProp(SearchPropPayload.builder()
.segment("downtown")
.build());
// By area
List<String> ids = client.searchProp(SearchPropPayload.builder()
.segment("downtown")
.area("manhattan")
.build());
// By location (radius search)
List<String> ids = client.searchProp(SearchPropPayload.builder()
.segment("downtown")
.latitude(40.7128)
.longitude(-74.0060)
.build());Checks if a property exists.
boolean exists = client.propExist("hotel_123");Checks if a specific room type exists for a property.
boolean exists = client.propRoomExist(PropRoomExistPayload.builder()
.propertyId("hotel_123")
.roomType("suite")
.build());Lists all room types for a property.
List<String> rooms = client.propRoomList("hotel_123");Lists dates with availability data for a property and room type.
List<String> dates = client.propRoomDateList(PropRoomDateListPayload.builder()
.propertyId("hotel_123")
.roomType("suite")
.build());Sets availability, price, and rate features for a room type on a date.
client.setRoomPkg(SetRoomPkgPayload.builder()
.propertyId("hotel_123")
.roomType("suite")
.date("2026-07-20")
.availability((short) 10)
.finalPrice(199)
.rateFeature(Arrays.asList("free_cancellation", "breakfast_included"))
.build());Sets exact availability for a room type on a specific date.
short newAvail = client.setRoomAvl(UpdRoomAvlPayload.builder()
.propertyId("hotel_123")
.roomType("suite")
.date("2026-07-20")
.amount((short) 20)
.build());Increases availability (e.g., on cancellation).
short newAvail = client.incRoomAvl(UpdRoomAvlPayload.builder()
.propertyId("hotel_123")
.roomType("suite")
.date("2026-07-20")
.amount((short) 1)
.build());Decreases availability (e.g., on booking).
short newAvail = client.decRoomAvl(UpdRoomAvlPayload.builder()
.propertyId("hotel_123")
.roomType("suite")
.date("2026-07-20")
.amount((short) 2)
.build());Gets availability and pricing for a specific room on a specific date.
GetRoomDayResult day = client.getPropRoomDay(GetRoomDayRequest.builder()
.propertyId("hotel_123")
.roomType("suite")
.date("2026-07-20")
.build());
System.out.println("Avail: " + day.getAvailability() + ", Price: " + day.getFinalPrice());Searches available rooms by filters.
List<PropertyAvail> results = client.searchAvail(SearchAvailPayload.builder()
.segment("downtown")
.roomType("suite")
.dates(Arrays.asList("2026-07-20", "2026-07-21"))
.limit(50L)
.minPrice(100)
.maxPrice(300)
.amenities(Arrays.asList("wifi", "pool"))
.rateFeature(Arrays.asList("free_cancellation"))
.build());
for (PropertyAvail result : results) {
System.out.println("Property: " + result.getPropertyId());
for (DayAvail day : result.getDays()) {
System.out.println(" " + day.getDate() + ": Avail " + day.getAvailability() +
", Price " + day.getFinalPrice());
}
}Lists all active segments with their property counts.
List<SegmentInfo> segments = client.getSegments();
for (SegmentInfo seg : segments) {
System.out.println(seg.getSegment() + ": " + seg.getCount() + " properties");
}Gets the current codec registry (used internally for validation).
Codecs codecs = client.getCodecs();
System.out.println(codecs.getRateFeatures());Deletes availability for a specific room on a specific date.
client.delRoomDay(DelRoomDayRequest.builder()
.propertyId("hotel_123")
.roomType("suite")
.date("2026-07-20")
.build());Deletes all data for a property on a specific date.
client.delPropDay(DelPropDayRequest.builder()
.propertyId("hotel_123")
.date("2026-07-20")
.build());Deletes a room type from a property.
client.delPropRoom(DelPropRoomPayload.builder()
.propertyId("hotel_123")
.roomType("suite")
.build());Deletes an entire property.
client.delProp("hotel_123");Deletes a segment and all properties within it.
client.delSegment("downtown");All methods throw RoomzinException. Use the helper methods to classify errors:
import com.roomzin.roomzinjava.internal.protocol.RoomzinException;
try {
client.setRoomPkg(payload);
} catch (RoomzinException e) {
if (e.isRequest()) {
// Business rule violation - fix the request
System.out.println("Request error: " + e.getCode());
} else if (e.isRetry()) {
// Temporary condition - retry with backoff
Thread.sleep(100);
client.setRoomPkg(payload);
} else if (e.isClient()) {
// Authentication or protocol errors
System.out.println("Client error: " + e.getMessage());
} else if (e.isInternal()) {
// Unexpected server response
throw new RuntimeException("Internal error", e);
} else {
// Fatal error
throw new RuntimeException("fatal", e);
}
}| Category | Description | Action |
|---|---|---|
| Client | Authentication or protocol errors | Check credentials and configuration |
| Request | Invalid input or business rule violation | Fix request, don't retry |
| Retry | Temporary server condition (429, 503, 308) | Retry with backoff |
| Internal | Unexpected server response | Log and investigate |
Create a single client during application startup and reuse it throughout your application.
// ✅ Good - create once, reuse
CacheClientApi client = SingleConfig.builder()
.withHost("127.0.0.1")
.withTcpPort(7777)
.withAuthToken("abc123")
.build();
// Use client everywhere...
client.close();
// ❌ Bad - creating per request
for (Request req : requests) {
CacheClientApi client = SingleConfig.builder() // Don't do this
.withHost("127.0.0.1")
.withTcpPort(7777)
.build();
client.setRoomPkg(req);
client.close();
}The client is safe for concurrent use and manages TCP connections internally.
For the complete interface definition, see CacheClientApi.java. All types are documented with Javadoc comments.
For Roomzin concepts, deployment, and administration:
https://m-javani.github.io/roomzin-doc/docs.html
Contributions are welcome! Please open an issue before proposing large changes.
All contributions are subject to the BUSL-1.1 License terms.
This SDK is licensed under the BUSL-1.1 License.
Note: This SDK communicates with Roomzin Server, which requires a valid Roomzin license.
- Documentation: roomzin-doc
- Community Q&A: GitHub Discussions
- Issues: GitHub Issues
- Security: mehdy.javany@gmail.com
- Roomzin Quickstart — Local Docker cluster
- Roomzin Bench — Benchmarking tool