Files
qbit-printing/dev/java/DevHost.java
T
james.maesandCodex 1a0964ef23 chore: enforce owned source copyright notices (#25)
* chore(standards): preserve owned-source copyright notices

Add accurate repository copyright and license comments to 50 owned source/build/configuration files. Preserve existing holders, upstream wrappers, legal payloads and schema/data exemptions. Exact inverse-byte reconstruction and applicable parser/token/AST checks prove comment-only changes; existing relevant regressions pass.

Co-Authored-By: Codex (GPT-6) <noreply@openai.com>
Signed-off-by: James Maes <james@kof22.com>

* chore: enforce owned source copyright notices

Check real leading comments against explicit repository provenance and retain existing native style gates.

Co-Authored-By: Codex GPT-6 <noreply@openai.com>
Signed-off-by: James Maes <james@kof22.com>

---------

Signed-off-by: James Maes <james@kof22.com>
Co-authored-by: Codex (GPT-6) <noreply@openai.com>
2026-11-01 12:41:00 -06:00

146 lines
6.1 KiB
Java

/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2026. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// SPDX-License-Identifier: Apache-2.0
package com.kingsrook.qbits.printing;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.module.filesystem.base.model.metadata.Cardinality;
import com.kingsrook.qqq.backend.module.filesystem.s3.model.metadata.S3BackendMetaData;
import com.kingsrook.qqq.backend.module.filesystem.s3.model.metadata.S3TableBackendDetails;
import com.kingsrook.qqq.backend.module.filesystem.s3.utils.S3ClientFactory;
import com.kingsrook.qqq.middleware.javalin.QApplicationLauncher;
import com.kingsrook.qqq.middleware.javalin.QApplicationLauncherConfig;
import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
import software.amazon.awssdk.services.s3.model.S3Exception;
/** Docker-only developer host. Compose publishes its port to host loopback only. */
public final class DevHost extends PrintingLocalHost
{
private static final String TABLE = "printing_documents";
private DevHost() throws Exception
{
super(new PrintingLocalSettings("jdbc:h2:file:/data/printing", "sa", required("QQQ_DATABASE_PASSWORD"), "development",
Integer.parseInt(required("QQQ_HTTP_PORT")), required("QQQ_MANAGEMENT_TOKEN"), "developer", required("QQQ_ADMIN_PASSWORD")));
}
public static void main(String[] args) throws Exception
{
waitStorage();
if(args.length == 1 && "--wait-storage".equals(args[0]))
{
return;
}
DevHost host = new DevHost();
QApplicationLauncher.run(host, new QApplicationLauncherConfig().withServerCustomizer(server ->
{
host.configure(server, true);
// Container interface only. The immutable Compose mapping binds host 127.0.0.1.
var original = server.getJavalinConfigCustomizer();
server.withJavalinConfigCustomizer(config ->
{
original.accept(config);
config.jetty.host = "0.0.0.0";
});
}));
}
@Override
public QInstance defineQInstance() throws QException
{
QInstance instance = super.defineQInstance();
S3BackendMetaData backend = new S3BackendMetaData().withName("printing_development_storage").withBucketName("printing-development")
.withEndpoint("http://127.0.0.1:9000").withPathStyleAccess(true).withRegion("us-east-1")
.withAccessKey(required("MINIO_ROOT_USER")).withSecretKey(required("MINIO_ROOT_PASSWORD"));
backend.setConnectTimeoutMillis(3000);
backend.setSocketTimeoutMillis(15000);
instance.addBackend(backend);
instance.addTable(new QTableMetaData().withName(TABLE).withBackendName(backend.getName())
.withBackendDetails(new S3TableBackendDetails().withCardinality(Cardinality.ONE).withFileNameFieldName("id").withContentsFieldName("content"))
.withPrimaryKeyField("id").withField(new QFieldMetaData("id", QFieldType.STRING)).withField(new QFieldMetaData("content", QFieldType.BLOB)));
var storage = S3ClientFactory.getClient(backend);
{
try
{
storage.headBucket(HeadBucketRequest.builder().bucket("printing-development").build());
}
catch(S3Exception missing)
{
if(missing.statusCode() != 404)
{
throw missing;
}
storage.createBucket(CreateBucketRequest.builder().bucket("printing-development").build());
}
}
PrintingQBitConfig config = instance.getQBits().values().stream().map(value -> value.getConfig())
.filter(PrintingQBitConfig.class::isInstance).map(PrintingQBitConfig.class::cast).findFirst().orElseThrow();
config.withStorageTableName(TABLE);
config.getService().configureStorage(instance, TABLE);
return instance;
}
private static void waitStorage() throws Exception
{
try(HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(2)).build())
{
long deadline = System.nanoTime() + Duration.ofSeconds(60).toNanos();
while(System.nanoTime() < deadline)
{
try
{
if(client.send(HttpRequest.newBuilder(URI.create("http://127.0.0.1:9000/minio/health/live"))
.timeout(Duration.ofSeconds(2)).GET().build(), HttpResponse.BodyHandlers.discarding()).statusCode() == 200)
{
return;
}
}
catch(java.io.IOException notReady)
{
// Only the fixture startup window retries; application work is never retried here.
}
Thread.sleep(200);
}
throw new IllegalStateException("Owned MinIO startup timed out");
}
}
private static String required(String name)
{
String value = System.getenv(name);
if(value == null || value.isBlank())
{
throw new IllegalArgumentException("Missing development environment setting: " + name);
}
return value;
}
}