package org.gcube.application.geoportal.service.engine.providers.ucd; import lombok.*; import lombok.extern.slf4j.Slf4j; import org.gcube.application.cms.caches.AbstractScopedMap; import org.gcube.application.cms.implementations.ISInterface; import org.gcube.application.cms.implementations.ImplementationProvider; import org.gcube.application.cms.serialization.Serialization; import org.gcube.application.geoportal.common.model.rest.ConfigurationException; import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor; import org.gcube.common.resources.gcore.GenericResource; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.*; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.GenericArrayType; import java.net.URL; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Scanner; /** * Retrieves available UCDs from a single Generic Resource * - secondary Type : "CMS" * - name : "UCDs" * * containing e.g. * * * * * * */ @Slf4j public class SingleISResourceUCDProvider extends AbstractScopedMap { public SingleISResourceUCDProvider() { super("Single IS Resource UCD Provider"); setTTL(Duration.of(2, ChronoUnit.MINUTES)); } @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "UCDs") @Data @EqualsAndHashCode public static class ISBean { @NoArgsConstructor @ToString @Getter @Setter @AllArgsConstructor @XmlAccessorType(XmlAccessType.FIELD) @EqualsAndHashCode public static class Record { @XmlAttribute private String label; @XmlAttribute private String ucdUrl; @XmlAttribute private String defaultForRegex; } @XmlElement(name = "record") private List records; } @Override public void init() { super.init(); try{ directInit(); }catch(Throwable t){ throw new RuntimeException("Unable to initialize. Can't read Use case descriptors ",t); } } static void directInit() throws JAXBException { jaxbContext = JAXBContext.newInstance(ISBean.class); marshaller = jaxbContext.createMarshaller(); unmarshaller = jaxbContext.createUnmarshaller(); } private static JAXBContext jaxbContext=null; private static Marshaller marshaller=null; private static Unmarshaller unmarshaller = null; static ISBean read(String xml) throws JAXBException { log.trace("Loading from xml {}",xml); return (ISBean) unmarshaller.unmarshal(new StringReader(xml)); } static String write(ISBean obj) throws JAXBException { log.trace("Writing {} to xml",obj); StringWriter writer = new StringWriter(); marshaller.marshal(obj,writer); writer.flush(); return writer.toString(); } @Override protected ProfileMap retrieveObject(String key) throws ConfigurationException { try { log.info("Loading UCDs for context {} ",key); ISInterface is = ImplementationProvider.get().getEngineByManagedClass(ISInterface.class); List l = is.getGenericResource("CMS","UCDs"); log.debug("Found {} resources ",l.size()); ProfileMap toReturn = new ProfileMap(); l.forEach(g->{ try { log.debug("Reading from ID {} ", g.id()); ISBean bean = read(g.profile().bodyAsString()); log.debug("Found {} records ", bean.getRecords().size()); int before = toReturn.size(); bean.getRecords().forEach(record -> { try { log.debug("Loading UCD From {} ", record); String json = new Scanner( new URL(record.getUcdUrl()).openStream(), "UTF-8").useDelimiter("\\A").next(); log.trace("JSON IS {} ",json); UseCaseDescriptor ucd = Serialization.read(json, UseCaseDescriptor.class); toReturn.put(ucd.getId(), ucd); }catch (Throwable t){ log.warn("Unable to read record {} from GR ID {} ",record,g.id(),t); } }); log.debug("Loaded {} from {} ",toReturn.size()-before,g.id()); }catch (Throwable t){ log.warn("Unable to read from GR {} ",g.id(),t); } }); return toReturn; }catch(Throwable t){ throw new ConfigurationException("Unable to load UCDs for "+key,t); } } }