001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2023-2026 The Enola <https://enola.dev> Authors 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package dev.enola.cli; 019 020import com.google.protobuf.ExtensionRegistryLite; 021import com.google.protobuf.Message; 022 023import dev.enola.common.io.iri.URIs; 024import dev.enola.common.io.resource.WritableResource; 025import dev.enola.common.io.resource.WriterResource; 026import dev.enola.common.protobuf.ProtoIO; 027import dev.enola.common.protobuf.TypeRegistryWrapper; 028import dev.enola.core.proto.EnolaServiceGrpc.EnolaServiceBlockingStub; 029import dev.enola.core.proto.GetFileDescriptorSetRequest; 030import dev.enola.core.view.EnolaMessages; 031import dev.enola.rdf.io.RdfWriterConverter; 032import dev.enola.rdf.proto.ProtoThingRdfConverter; 033import dev.enola.thing.gen.graphcommons.GraphCommonsJsonGenerator; 034import dev.enola.thing.gen.graphviz.GraphvizGenerator; 035import dev.enola.thing.message.ProtoThings; 036import dev.enola.thing.metadata.ThingMetadataProvider; 037import dev.enola.thing.proto.Thing; 038import dev.enola.thing.proto.Things; 039import dev.enola.web.EnolaThingProvider; 040 041import org.eclipse.rdf4j.model.impl.SimpleValueFactory; 042import org.eclipse.rdf4j.model.util.ModelBuilder; 043import org.eclipse.rdf4j.rio.helpers.StatementCollector; 044 045import picocli.CommandLine; 046 047import java.io.IOException; 048 049public abstract class CommandWithIRI extends CommandWithModelAndOutput { 050 051 @CommandLine.Option( 052 names = {"--format", "-f"}, 053 required = true, 054 defaultValue = "Turtle", 055 description = "Output Format: ${COMPLETION-CANDIDATES}; default=${DEFAULT-VALUE}") 056 Format format; 057 058 // TODO @Parameters(index = "0..*") List<String> eris; 059 @CommandLine.Parameters(index = "0", paramLabel = "iri", description = "IRI of Thing") 060 String iri; 061 062 private WritableResource resource; 063 private TypeRegistryWrapper typeRegistryWrapper; 064 protected EnolaMessages enolaMessages; 065 private ThingMetadataProvider thingMetadataProvider; 066 067 @Override 068 protected final void run(EnolaServiceBlockingStub service) throws Exception { 069 thingMetadataProvider = getMetadataProvider(new EnolaThingProvider(service)); 070 071 var gfdsr = GetFileDescriptorSetRequest.newBuilder().build(); 072 var fds = service.getFileDescriptorSet(gfdsr).getProtos(); 073 typeRegistryWrapper = TypeRegistryWrapper.from(fds); 074 var extensionRegistry = ExtensionRegistryLite.getEmptyRegistry(); 075 enolaMessages = new EnolaMessages(typeRegistryWrapper, extensionRegistry); 076 077 // See CommandWithModelAndOutput 078 if (output == null || output.output.equals(Output.DEFAULT_OUTPUT_URI)) { 079 resource = new WriterResource(spec.commandLine().getOut(), format.toMediaType()); 080 } else { 081 resource = 082 rp.getWritableResource( 083 URIs.addMediaType(Output.get(output), format.toMediaType())); 084 } 085 086 run(service, iri); 087 } 088 089 protected abstract void run(EnolaServiceBlockingStub service, String eri) throws Exception; 090 091 protected void write(Message thing) throws IOException { 092 if (Format.Turtle.equals(format) || Format.JSONLD.equals(format)) { 093 var model = new ModelBuilder().build(); 094 var statementCollector = new StatementCollector(model); 095 if (thing instanceof Thing protoThing) { 096 var vf = SimpleValueFactory.getInstance(); 097 new ProtoThingRdfConverter(vf).convertInto(protoThing, statementCollector); 098 } else if (thing instanceof Things protoThings) { 099 for (var protoThing : protoThings.getThingsList()) 100 new ProtoThingRdfConverter().convertInto(protoThing, statementCollector); 101 } 102 new RdfWriterConverter().convertIntoOrThrow(model, resource); 103 return; 104 } 105 106 if (Format.Graphviz.equals(format) && thing instanceof Things protoThings) { 107 var javaThings = ProtoThings.proto2java(protoThings.getThingsList()); 108 new GraphvizGenerator(thingMetadataProvider).convertIntoOrThrow(javaThings, resource); 109 return; 110 } 111 112 if (Format.GraphCommons.equals(format) && thing instanceof Things protoThings) { 113 var javaThings = ProtoThings.proto2java(protoThings.getThingsList()); 114 new GraphCommonsJsonGenerator(thingMetadataProvider) 115 .convertIntoOrThrow(javaThings, resource); 116 return; 117 } 118 119 // Otherwise 120 new ProtoIO(typeRegistryWrapper.get()).write(thing, resource); 121 } 122}