Java Development

Main concepts

In order to access the Odilon server from a Java Application you have to include Odilon client JAR in the classpath. The interaction is managed by an instance of OdilonClient that connects to the server using the credentials: AccessKey (ie. username) and SecretKey (ie. password)


/* these are the default values for the Server */
String endpoint = "http://localhost";
int port = 9234;
String accessKey = "odilon";
String secretKey = "odilon";
						
/** OdilonClient is the interface, ODClient is the implementation */
OdilonClient client = new ODClient(endpoint, port, accessKey, secretKey);

/** ping checks the status of server, it returns the String "ok" when the server is normal */
String ping = client.ping();
if (!ping.equals("ok")) {
	System.out.println("ping error -> " + ping);
	System.exit(1);
}

The client can also be created using the builder pattern, which sets the connection parameters with a fluent API:


/** ODClient.builder() returns a Builder to construct an ODClient instance using a fluent API */
OdilonClient client = ODClient.builder()
		.endpoint("http://localhost")
		.port(9234)
		.accessKey("odilon")
		.secretKey("odilon")
		.build();

Odilon stores objects using a flat structure of containers called Buckets. A bucket is like a folder, it just contains binary objects, potentially a very large number. Every object contained by a bucket has a unique ObjectName in that bucket; therefore, the pair BucketName + ObjectName is a Unique ID for each object in Odilon.


try {
    String bucketName = "bucket-demo";
    /** check if the bucket exists, if not create it */
    if (client.existsBucket(bucketName))
        System.out.println("bucket already exists ->" + bucketName );
    else 
        client.createBucket(bucketName);
} catch (ODClientException e) {
System.out.println(String.valueOf(e.getHttpStatus())+ " " + e.getMessage()+" " + String.valueOf(e.getErrorCode())); }

Uploading a File requires the Bucket to exist and the ObjectName to be unique for that bucket.


File file = new File("test.pdf");
String bucketName = "bucket-demo";
String objectName = file.getName();

try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {	
	client.putObjectStream(bucketName, objectName, inputStream, Optional.of(file.getName()), Optional.empty());
} catch (ODClientException e) {
	System.out.println(String.valueOf(e.getHttpStatus())+" " + e.getMessage()+" " + String.valueOf(e.getErrorCode()));
} catch (FileNotFoundException | IOException e1) {
	System.out.println(e1.getClass().getName() + " " + e1.getMessage());
}



					

Listing bucket's objects

In addition to the binary file, an Object has Metadata (called ObjectMetadata) that is returned by some of the API calls. Odilon allows to retrieve Objects individually by BucketName + ObjectName and also supports to list the contents of a bucket and other simple queries.


try {
	/** list all bucket's objects */
	ResultSet<Item <ObjectMetadata>> resultSet = client.listObjects(bucket.getName());
	while (resultSet.hasNext()) {
		Item item = resultSet.next();
		if (item.isOk())
			System.out.println("ObjectName:"+item.getObject().objectName+" | file: " + item.getObject().fileName);
		else
			System.out.println(item.getErrorString());
	}
} catch (ODClientException e) {
   	System.out.println(String.valueOf( e.getHttpStatus())+ " "+e.getMessage() + " "+String.valueOf(e.getErrorCode()));
}

							

					

Besides listObjects, which returns a paginated ResultSet, the client can query the server's embedded Apache Lucene index with search(SearchQuery). A search returns a List<SearchResult> with up to 1000 items per call (use offset and maxResults to page through larger results). Search must be enabled on the server (search.enabled=true). See Queries for details and REST examples.


try {
	/** free text over object name, file name, tags and metadata values */
	SearchQuery q1 = new SearchQuery().q("invoice").maxResults(50);
	for (SearchResult r : client.search(q1))
		System.out.println(r.bucketName + "/" + r.objectName + " | " + r.fileName + " | score " + r.score);

	/** file name wildcard + bucket + metadata + date range */
	SearchQuery q2 = new SearchQuery()
			.bucketName("docs")
			.fileName("tolomei*")
			.meta("department", "legal")
			.lastModifiedFrom(OffsetDateTime.parse("2026-01-01T00:00:00Z"))
			.lastModifiedTo(OffsetDateTime.parse("2026-09-30T23:59:59Z"))
			.offset(0)
			.maxResults(100);

	List<SearchResult> results = client.search(q2);
	results.forEach(r -> System.out.println(r));

	/** index status and rebuild */
	IndexStatus status = client.searchStatus();
	boolean started = client.searchRebuild();
} catch (ODClientException e) {
	System.out.println(String.valueOf(e.getHttpStatus()) + " " + e.getMessage() + " " + String.valueOf(e.getErrorCode()));
}

Sample programs

Create Bucket

SampleBucketCreation.java


List Buckets

SampleListBuckets.java


Upload file

Sample putObject and download ObjectMetadata
SamplePutObject.java


List all objects in a Bucket

SampleListObjects.java


Get presigned urls of Objects

A presigned URL is a method to grant temporary access to an Object, for example in an HTML webpage. It remains valid for a limited period of time which is specified when the URL is generated. This example shows presigned urls that last 7 days and 5 minutes.
SamplePresignedUrl.java

This unit test example downloads presigned urls from a Bucket.
TestPresignedUrl.java


Minio to Odilon migration

This class shows how to migrate from Minio Object Storage to Odilon (it uses Minio SDK 6.x). It is a multithreaded gateway that iterates reading a buffer of items from Minio and sending them in parallel to Odilon.

https://github.com/atolomei/miniomigration


Dellemuse - Object Storage Service

Dellemuse is a free service that enriches the cultural experience in museums and historical buildings through AI-generated audio guides that visitors can listen to on their mobile phones. It uses Odilon to store images, audio and other files. The server is a Spring Boot Java application that uses PostgreSQL and Odilon for data storage. For Odilon, it has a thin service layer called ObjectStorageService
Dellemuse ObjectStorageService


Odilon SDK Javadoc

SDK Javadoc