001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2024-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.web; 019 020import com.google.protobuf.Descriptors.DescriptorValidationException; 021import com.google.protobuf.ExtensionRegistryLite; 022import com.google.protobuf.InvalidProtocolBufferException; 023 024import dev.enola.common.protobuf.TypeRegistryWrapper; 025import dev.enola.core.proto.EnolaServiceGrpc.EnolaServiceBlockingStub; 026import dev.enola.core.proto.GetFileDescriptorSetRequest; 027import dev.enola.core.proto.GetThingRequest; 028import dev.enola.core.thing.ListThingService; 029import dev.enola.core.view.EnolaMessages; 030import dev.enola.data.Repository; 031import dev.enola.thing.message.MessageToThingConverter; 032import dev.enola.thing.message.MessageWithIRI; 033import dev.enola.thing.message.MoreThings; 034import dev.enola.thing.proto.Thing; 035 036import java.io.IOException; 037import java.io.UncheckedIOException; 038import java.util.ArrayList; 039 040public class EnolaThingProvider implements Repository<Thing> { 041 042 // TODO Replace everywhere with EnolaServiceProtoThingsProvider 043 // TODO implements ProtoThingRepository, ProtoThingProvider 044 // TODO Move into dev.enola.core.thing where it probably belongs, more logically? 045 // TODO Resolve (some) overlap this class has with abstract class ProtoToThingConnector 046 // TODO Resolve (some) overlap this class has with abstract class ThingConnectorsProvider 047 048 private final MessageToThingConverter m2t = new MessageToThingConverter(); 049 private final EnolaServiceBlockingStub service; 050 private final EnolaMessages enolaMessages; 051 052 public EnolaThingProvider(EnolaServiceBlockingStub service) 053 throws DescriptorValidationException { 054 this.service = service; 055 056 var gfdsr = GetFileDescriptorSetRequest.newBuilder().build(); 057 var fds = service.getFileDescriptorSet(gfdsr).getProtos(); 058 TypeRegistryWrapper typeRegistryWrapper = TypeRegistryWrapper.from(fds); 059 var extensionRegistry = ExtensionRegistryLite.getEmptyRegistry(); 060 enolaMessages = new EnolaMessages(typeRegistryWrapper, extensionRegistry); 061 } 062 063 @Override 064 public Thing get(String iri) { 065 var request = GetThingRequest.newBuilder().setIri(iri).build(); 066 var response = service.getThing(request); 067 068 if (!response.hasThing()) { 069 return null; 070 } 071 var any = response.getThing(); 072 073 try { 074 var things = MoreThings.fromAny(any); 075 if (!things.isEmpty()) { 076 // TODO This is wrong, we need to return Things here, and UI needs to show all? 077 return things.getFirst(); 078 } else { 079 var message = enolaMessages.toMessage(any); 080 return m2t.convert(new MessageWithIRI(iri, message)).build(); 081 } 082 } catch (IOException e) { 083 throw new UncheckedIOException(e); 084 } 085 } 086 087 @Override 088 public Iterable<Thing> list() { 089 var iri = ListThingService.ENOLA_ROOT_LIST_THINGS; 090 var request = GetThingRequest.newBuilder().setIri(iri).build(); 091 var response = service.getThing(request); 092 if (!response.hasThing()) throw new IllegalArgumentException(); 093 var any = response.getThing(); 094 try { 095 return MoreThings.fromAny(any); 096 } catch (InvalidProtocolBufferException e) { 097 throw new UncheckedIOException(e); 098 } 099 } 100 101 @Override 102 public Iterable<String> listIRI() { 103 var listProtoThing = get(ListThingService.ENOLA_ROOT_LIST_IRIS); 104 var valueList = 105 listProtoThing 106 .getPropertiesMap() 107 .get(ListThingService.ENOLA_ROOT_LIST_PROPERTY) 108 .getList() 109 .getValuesList(); 110 var iriList = new ArrayList<String>(valueList.size()); 111 for (var value : valueList) { 112 if (value.hasLink()) { 113 iriList.add(value.getLink()); 114 } 115 } 116 return iriList; 117 } 118}