diff --git a/indexer/src/main/java/au/org/aodn/esindexer/service/IndexerServiceImpl.java b/indexer/src/main/java/au/org/aodn/esindexer/service/IndexerServiceImpl.java index 22992adf..fee2c381 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/service/IndexerServiceImpl.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/service/IndexerServiceImpl.java @@ -34,34 +34,40 @@ @Service public class IndexerServiceImpl implements IndexerService { - @Autowired - GeoNetworkService geoNetworkResourceService; - - @Autowired - ElasticsearchClient portalElasticsearchClient; - - @Autowired - ElasticSearchIndexService elasticSearchIndexService; - - @Value("${elasticsearch.index.name}") - private String indexName; - - @Autowired - ObjectMapper indexerObjectMapper; - - @Autowired + protected String indexName; + protected GeoNetworkService geoNetworkResourceService; + protected ElasticsearchClient portalElasticsearchClient; + protected ElasticSearchIndexService elasticSearchIndexService; + protected ObjectMapper indexerObjectMapper; protected StacCollectionMapperService stacCollectionMapperService; + protected JaxbUtils jaxbUtils; + protected RankingService rankingService; + protected AodnDiscoveryParameterVocabService aodnDiscoveryParameterVocabService; - @Autowired - JaxbUtils jaxbUtils; - - @Autowired - RankingService rankingService; + private static final Logger logger = LogManager.getLogger(IndexerServiceImpl.class); @Autowired - AodnDiscoveryParameterVocabService aodnDiscoveryParameterVocabService; - - private static final Logger logger = LogManager.getLogger(IndexerServiceImpl.class); + public IndexerServiceImpl( + @Value("${elasticsearch.index.name}") String indexName, + ObjectMapper indexerObjectMapper, + JaxbUtils jaxbUtils, + RankingService rankingService, + GeoNetworkService geoNetworkResourceService, + ElasticsearchClient portalElasticsearchClient, + ElasticSearchIndexService elasticSearchIndexService, + StacCollectionMapperService stacCollectionMapperService, + AodnDiscoveryParameterVocabService aodnDiscoveryParameterVocabService + ) { + this.indexName = indexName; + this.indexerObjectMapper = indexerObjectMapper; + this.jaxbUtils = jaxbUtils; + this.rankingService = rankingService; + this.geoNetworkResourceService = geoNetworkResourceService; + this.portalElasticsearchClient = portalElasticsearchClient; + this.elasticSearchIndexService = elasticSearchIndexService; + this.stacCollectionMapperService = stacCollectionMapperService; + this.aodnDiscoveryParameterVocabService = aodnDiscoveryParameterVocabService; + } public Hit getDocumentByUUID(String uuid) throws IOException { try { @@ -175,7 +181,7 @@ public ResponseEntity indexMetadata(String metadataValues) { if (this.isMetadataPublished(uuid)) { try(InputStream is = new ByteArrayInputStream(indexerObjectMapper.writeValueAsBytes(mappedMetadataValues))) { logger.info("Ingesting a new metadata with UUID: " + uuid + " to index: " + indexName); - logger.info("{}", mappedMetadataValues); + logger.debug("{}", mappedMetadataValues); req = IndexRequest.of(b -> b .index(indexName) .withJson(is)); diff --git a/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java b/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java index 832baabb..2236adf2 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java @@ -3,13 +3,12 @@ import au.org.aodn.esindexer.exception.MappingValueException; import au.org.aodn.esindexer.utils.GeometryUtils; import au.org.aodn.esindexer.configuration.AppConstants; -import au.org.aodn.esindexer.utils.UrlUtils; +import au.org.aodn.esindexer.utils.MapperUtils; import au.org.aodn.stac.model.*; import au.org.aodn.esindexer.utils.BBoxUtils; import au.org.aodn.esindexer.utils.TemporalUtils; import au.org.aodn.metadata.iso19115_3_2018.*; -import com.fasterxml.jackson.databind.JsonNode; import jakarta.xml.bind.JAXBElement; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -27,7 +26,6 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.*; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.stream.Collectors; @@ -90,7 +88,7 @@ List mapExtentTemporal(MDMetadataType source) { List createExtentTemporal(MDMetadataType source) { - List items = findMDDataIdentificationType(source); + List items = MapperUtils.findMDDataIdentificationType(source); if (items.isEmpty()) { logger.warn("Unable to find extent temporal information for metadata record: " + this.mapUUID(source)); return null; @@ -181,7 +179,7 @@ private String convertDateToZonedDateTime(String inputDateString) { */ @Named("mapDescription") String mapDescription(MDMetadataType source) { - List items = findMDDataIdentificationType(source); + List items = MapperUtils.findMDDataIdentificationType(source); if(!items.isEmpty()) { // Need to assert only 1 block contains our target @@ -221,7 +219,7 @@ Map mapSummariesGeometry(MDMetadataType source) { @Named("mapSummaries.status") String createSummariesStatus(MDMetadataType source) { - List items = findMDDataIdentificationType(source); + List items = MapperUtils.findMDDataIdentificationType(source); if (!items.isEmpty()) { List temp = new ArrayList<>(); for (MDDataIdentificationType i : items) { @@ -239,7 +237,7 @@ String createSummariesStatus(MDMetadataType source) { @Named("mapSummaries.scope") Map createSummariesScope(MDMetadataType source) { - List items = findMDMetadataScopePropertyType(source); + List items = MapperUtils.findMDMetadataScopePropertyType(source); if (!items.isEmpty()) { for (MDMetadataScopeType i : items) { @@ -263,7 +261,7 @@ Map createSummariesScope(MDMetadataType source) { */ @Named("mapTitle") String mapTitle(MDMetadataType source) { - List items = findMDDataIdentificationType(source); + List items = MapperUtils.findMDDataIdentificationType(source); if(!items.isEmpty()) { // Need to assert only 1 block contains our target for(MDDataIdentificationType i : items) { @@ -389,7 +387,7 @@ protected String mapThemesScheme(MDKeywordsPropertyType descriptiveKeyword, Stri @Named("mapThemes") List mapThemes(MDMetadataType source) { List results = new ArrayList<>(); - List items = findMDDataIdentificationType(source); + List items = MapperUtils.findMDDataIdentificationType(source); if (!items.isEmpty()) { for (MDDataIdentificationType i : items) { i.getDescriptiveKeywords().forEach(descriptiveKeyword -> { @@ -411,7 +409,7 @@ List mapThemes(MDMetadataType source) { List mapLinks(MDMetadataType source) { final List results = new ArrayList<>(); - List items = findMDDistributionType(source); + List items = MapperUtils.findMDDistributionType(source); if (!items.isEmpty()) { for (MDDistributionType i : items) { i.getTransferOptions().forEach(transferOption -> transferOption.getMDDigitalTransferOptions().getOnLine().forEach(link -> { @@ -482,7 +480,7 @@ List mapProviders(MDMetadataType source) { @Named("mapLicense") String mapLicense(MDMetadataType source) { - List items = findMDDataIdentificationType(source); + List items = MapperUtils.findMDDataIdentificationType(source); List potentialKeys = Arrays.asList("license", "creative commons"); List licenses = new ArrayList<>(); if (!items.isEmpty()) { @@ -519,81 +517,112 @@ String mapLicense(MDMetadataType source) { return ""; } } - + /** + * A sample of contact block will be like this, you can have individual block and organization block together + * + * @param source + * @return + */ @Named("mapContacts") List mapContacts(MDMetadataType source) { List results = new ArrayList<>(); - List items = findMDDataIdentificationType(source); + List items = MapperUtils.findMDDataIdentificationType(source); if (!items.isEmpty()) { for (MDDataIdentificationType item : items) { item.getPointOfContact().forEach(poc -> { if (poc.getAbstractResponsibility() != null) { AbstractResponsibilityType responsibilityType = poc.getAbstractResponsibility().getValue(); - if (responsibilityType instanceof CIResponsibilityType2 ciResponsibility) { - ContactsModel contactsModel = ContactsModel.builder().build(); - contactsModel.setRoles(mapContactsRole(ciResponsibility)); + if (responsibilityType instanceof final CIResponsibilityType2 ciResponsibility) { if (ciResponsibility.getParty().isEmpty()) { logger.warn("Unable to find contact info for metadata record: " + this.mapUUID(source)); } else { ciResponsibility.getParty().forEach(party -> { - contactsModel.setOrganization(mapContactsOrganization(party)); - try { - AtomicReference name = new AtomicReference<>(""); - AtomicReference position = new AtomicReference<>(""); - List> addresses = new ArrayList<>(); - List emailAddresses = new ArrayList<>(); - List> phones = new ArrayList<>(); - List> onlineResources = new ArrayList<>(); + if(party.getAbstractCIParty() != null + && party.getAbstractCIParty().getValue() != null + && party.getAbstractCIParty().getValue() instanceof CIOrganisationType2 organisation) { + + // Extract organizational level contact + Optional org = MapperUtils.mapContactInfo(organisation.getContactInfo()); + + // We have individual contact? + if(organisation.getIndividual() != null && !organisation.getIndividual().isEmpty()) { + results.addAll(organisation + .getIndividual() + .stream() + .map(individual -> { + ContactsModel invContactsModel = ContactsModel.builder().build(); + invContactsModel.setName(MapperUtils.mapContactsName(individual)); + invContactsModel.setPosition(MapperUtils.mapContactsPosition(individual)); + invContactsModel.setRoles(MapperUtils.mapContactsRole(ciResponsibility)); + invContactsModel.setOrganization(organisation.getName().getCharacterString().getValue().toString()); + + Optional inv = MapperUtils.mapContactInfo(individual.getCIIndividual().getContactInfo()); + MapperUtils.Contacts i = org.orElse(null); + + // Address + if(inv.isPresent() && !inv.get().getAddresses().isEmpty()) { + invContactsModel.setAddresses(inv.get().getAddresses()); + } + else { + invContactsModel.setAddresses(i != null ? i.getAddresses() : null); + } + // Email + if(inv.isPresent() && !inv.get().getEmails().isEmpty()) { + invContactsModel.setEmails(inv.get().getEmails()); + } + else { + invContactsModel.setEmails(i != null ? i.getEmails() : null); + } + // Phone + if(inv.isPresent() && !inv.get().getPhones().isEmpty()) { + invContactsModel.setPhones(inv.get().getPhones()); + } + else { + invContactsModel.setPhones(i != null ? i.getPhones() : null); + } + // Online Resources + // Phone + if(inv.isPresent() && !inv.get().getOnlineResources().isEmpty()) { + invContactsModel.setLinks(inv.get().getOnlineResources()); + } + else { + invContactsModel.setLinks(i != null ? i.getOnlineResources() : null); + } + + return invContactsModel; + }) + .toList()); + } + else { + ContactsModel orgContactsModel = ContactsModel.builder().build(); + orgContactsModel.setRoles(MapperUtils.mapContactsRole(ciResponsibility)); + orgContactsModel.setOrganization(MapperUtils.mapContactsOrganization(party)); + orgContactsModel.setOrganization(organisation.getName().getCharacterString().getValue().toString()); + if(org.isPresent() && !org.get().getAddresses().isEmpty()) { + orgContactsModel.setAddresses(org.get().getAddresses()); + } - CIOrganisationType2 organisation = (CIOrganisationType2) party.getAbstractCIParty().getValue(); - AtomicReference> contactInfoList = new AtomicReference<>(); + if(org.isPresent() && !org.get().getEmails().isEmpty()) { + orgContactsModel.setEmails(org.get().getEmails()); + } - if (organisation.getIndividual().isEmpty()) { - contactInfoList.set(organisation.getContactInfo()); - } - else { - organisation.getIndividual().forEach(individual -> { - name.set(mapContactsName(individual)); - position.set(mapContactsPosition(individual)); - contactInfoList.set(individual.getCIIndividual().getContactInfo()); - }); - } + if(org.isPresent() && !org.get().getPhones().isEmpty()) { + orgContactsModel.setPhones(org.get().getPhones()); + } - contactInfoList.get().forEach(contactInfo -> contactInfo.getCIContact().getAddress().forEach(address -> { - // addresses - addresses.add(mapContactsAddress(address)); - // emails - address.getCIAddress().getElectronicMailAddress().forEach(electronicMailAddress -> { - emailAddresses.add(mapContactsEmail(electronicMailAddress)); - }); - // phones - contactInfo.getCIContact().getPhone().forEach(phone -> { - phones.add(mapContactsPhone(phone)); - }); - // online resources - contactInfo.getCIContact().getOnlineResource().forEach(onlineResource -> { - onlineResources.add(mapContactsOnlineResource(onlineResource)); - }); - })); - - contactsModel.setName(name.get()); - contactsModel.setPosition(position.get()); - contactsModel.setAddresses(addresses); - contactsModel.setEmails(emailAddresses); - contactsModel.setPhones(phones); - contactsModel.setLinks(onlineResources); + if(org.isPresent() && !org.get().getOnlineResources().isEmpty()) { + orgContactsModel.setLinks(org.get().getOnlineResources()); + } - } - catch (Exception e) { - logger.warn("Unable to find contact info for metadata record: {}", mapUUID(source)); + results.add(orgContactsModel); + } } }); - results.add(contactsModel); } } } @@ -606,101 +635,16 @@ List mapContacts(MDMetadataType source) { return results; } - protected String mapContactsRole(CIResponsibilityType2 ciResponsibility) { - CodeListValueType roleCode = ciResponsibility.getRole().getCIRoleCode(); - return roleCode != null ? - roleCode.getCodeListValue() : ""; - } - - protected String mapContactsOrganization(AbstractCIPartyPropertyType2 party) { - String organisationString = ""; - if (party.getAbstractCIParty() != null) { - if (party.getAbstractCIParty().getValue().getName().getCharacterString() != null) { - organisationString = party.getAbstractCIParty().getValue().getName().getCharacterString().getValue().toString(); - } - } - return organisationString; - } - - protected String mapContactsName(CIIndividualPropertyType2 individual) { - CharacterStringPropertyType nameString = individual.getCIIndividual().getName(); - return nameString != null ? - individual.getCIIndividual().getName().getCharacterString().getValue().toString() : ""; - } - - protected String mapContactsPosition(CIIndividualPropertyType2 individual) { - CharacterStringPropertyType positionString = individual.getCIIndividual().getPositionName(); - return positionString != null ? - individual.getCIIndividual().getPositionName().getCharacterString().getValue().toString() : ""; - } - - protected Map mapContactsAddress(CIAddressPropertyType2 address) { - Map addressItem = new HashMap<>(); - List deliveryPoints = new ArrayList<>(); - - address.getCIAddress().getDeliveryPoint().forEach(deliveryPoint -> { - String deliveryPointString = deliveryPoint.getCharacterString().getValue().toString(); - deliveryPoints.add(deliveryPointString != null ? deliveryPointString : ""); - }); - addressItem.put("deliveryPoint", deliveryPoints); - - CharacterStringPropertyType cityString = address.getCIAddress().getCity(); - addressItem.put("city", cityString != null ? cityString.getCharacterString().getValue().toString() : ""); - - CharacterStringPropertyType administrativeAreaString = address.getCIAddress().getAdministrativeArea(); - addressItem.put("administrativeArea", administrativeAreaString != null ? administrativeAreaString.getCharacterString().getValue().toString() : ""); - - CharacterStringPropertyType postalCodeString = address.getCIAddress().getPostalCode(); - addressItem.put("postalCode", postalCodeString != null ? postalCodeString.getCharacterString().getValue().toString() : ""); - - CharacterStringPropertyType countryString = address.getCIAddress().getCountry(); - addressItem.put("country", countryString != null ? countryString.getCharacterString().getValue().toString() : ""); - - return addressItem; - } - - protected String mapContactsEmail(CharacterStringPropertyType electronicMailAddress) { - return electronicMailAddress != null ? - electronicMailAddress.getCharacterString().getValue().toString() : ""; - } - - protected Map mapContactsPhone(CITelephonePropertyType2 phone) { - Map phoneItem = new HashMap<>(); - - CharacterStringPropertyType phoneString = phone.getCITelephone().getNumber(); - phoneItem.put("value", phoneString != null ? phoneString.getCharacterString().getValue().toString() : ""); - - CodeListValueType phoneCode = phone.getCITelephone().getNumberType().getCITelephoneTypeCode(); - phoneItem.put("roles", phoneCode != null ? phoneCode.getCodeListValue() : ""); - - return phoneItem; - } - - protected Map mapContactsOnlineResource(CIOnlineResourcePropertyType2 onlineResource) { - Map onlineResourceItem = new HashMap<>(); - - CharacterStringPropertyType linkString = onlineResource.getCIOnlineResource().getLinkage(); - onlineResourceItem.put("href", linkString != null ? linkString.getCharacterString().getValue().toString() : ""); - - CharacterStringPropertyType resourceNameString = onlineResource.getCIOnlineResource().getName(); - onlineResourceItem.put("title", resourceNameString != null ? resourceNameString.getCharacterString().getValue().toString() : ""); - - CharacterStringPropertyType linkTypeString = onlineResource.getCIOnlineResource().getProtocol(); - onlineResourceItem.put("type", linkTypeString != null ? linkTypeString.getCharacterString().getValue().toString() : ""); - - return onlineResourceItem; - } - @Named("mapLanguages") protected List mapLanguages(MDMetadataType source) { List results = new ArrayList<>(); - List items = findMDDataIdentificationType(source); + List items = MapperUtils.findMDDataIdentificationType(source); if (!items.isEmpty()) { for (MDDataIdentificationType i : items) { LanguageModel languageModel = LanguageModel.builder().build(); - String langCode = mapLanguagesCode(i) != null ? mapLanguagesCode(i) : ""; + String langCode = MapperUtils.mapLanguagesCode(i) != null ? MapperUtils.mapLanguagesCode(i) : ""; languageModel.setCode(langCode); // all metadata records are in English anyway @@ -720,22 +664,12 @@ protected List mapLanguages(MDMetadataType source) { return results; } - protected String mapLanguagesCode(MDDataIdentificationType i) { - try { - return i.getDefaultLocale().getPTLocale().getValue().getLanguage().getLanguageCode().getCodeListValue(); - } - catch (NullPointerException e) { - return null; - } - } - - protected R createGeometryItems( MDMetadataType source, Function, R> exBoundingPolygonTypeHandler, Function, R> exGeographicBoundingBoxTypeHandler) { - List items = findMDDataIdentificationType(source); + List items = MapperUtils.findMDDataIdentificationType(source); if(!items.isEmpty()) { // Need to assert only 1 block contains our target for(MDDataIdentificationType i : items) { @@ -784,33 +718,4 @@ else if (!rawInput.isEmpty() && rawInput.get(0) instanceof EXGeographicBoundingB } return null; } - - protected List findMDDataIdentificationType(MDMetadataType source) { - // Read the raw XML to understand the structure. - return source.getIdentificationInfo() - .stream() - .filter(f -> f.getAbstractResourceDescription() != null) - .filter(f -> f.getAbstractResourceDescription().getValue() != null) - .filter(f -> f.getAbstractResourceDescription().getValue() instanceof MDDataIdentificationType) - .map(f -> (MDDataIdentificationType)f.getAbstractResourceDescription().getValue()) - .collect(Collectors.toList()); - } - - protected List findMDMetadataScopePropertyType(MDMetadataType source) { - return source.getMetadataScope() - .stream() - .map(MDMetadataScopePropertyType::getMDMetadataScope) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - protected List findMDDistributionType(MDMetadataType source) { - return source.getDistributionInfo() - .stream() - .filter(f -> f.getAbstractDistribution() != null) - .filter(f -> f.getAbstractDistribution().getValue() != null) - .filter(f -> f.getAbstractDistribution().getValue() instanceof MDDistributionType) - .map(f -> (MDDistributionType)f.getAbstractDistribution().getValue()) - .collect(Collectors.toList()); - } } diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/MapperUtils.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/MapperUtils.java new file mode 100644 index 00000000..e928ccbf --- /dev/null +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/MapperUtils.java @@ -0,0 +1,407 @@ +package au.org.aodn.esindexer.utils; + +import au.org.aodn.metadata.iso19115_3_2018.*; +import au.org.aodn.stac.model.ContactsAddressModel; +import au.org.aodn.stac.model.ContactsPhoneModel; +import au.org.aodn.stac.model.LinkModel; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.*; +import java.util.stream.Collectors; + +public class MapperUtils { + + @Getter + @Setter + @Builder + public static class Contacts { + + @Builder.Default + protected LinkedHashSet addresses = new LinkedHashSet<>(); + + @Builder.Default + protected LinkedHashSet phones = new LinkedHashSet<>(); + + @Builder.Default + protected LinkedHashSet emails = new LinkedHashSet<>(); + + @Builder.Default + protected LinkedHashSet onlineResources = new LinkedHashSet<>(); + } + + public static String mapContactsRole(CIResponsibilityType2 ciResponsibility) { + CodeListValueType roleCode = ciResponsibility.getRole().getCIRoleCode(); + return roleCode != null ? + roleCode.getCodeListValue() : ""; + } + + public static String mapContactsOrganization(AbstractCIPartyPropertyType2 party) { + String organisationString = ""; + if (party.getAbstractCIParty() != null) { + if (party.getAbstractCIParty().getValue().getName().getCharacterString() != null) { + organisationString = party.getAbstractCIParty().getValue().getName().getCharacterString().getValue().toString(); + } + } + return organisationString; + } + + public static String mapContactsName(CIIndividualPropertyType2 individual) { + CharacterStringPropertyType nameString = individual.getCIIndividual().getName(); + return nameString != null ? + individual.getCIIndividual().getName().getCharacterString().getValue().toString() : ""; + } + + public static String mapContactsPosition(CIIndividualPropertyType2 individual) { + CharacterStringPropertyType positionString = individual.getCIIndividual().getPositionName(); + return positionString != null ? + individual.getCIIndividual().getPositionName().getCharacterString().getValue().toString() : ""; + } + /** + * Attribute will not be there if it is empty, this align with what Elastic handle null or empty field. + * @param address + * @return + */ + public static ContactsAddressModel mapContactsAddress(CIAddressPropertyType2 address) { + ContactsAddressModel addressItem = ContactsAddressModel.builder().build(); + List deliveryPoints = new ArrayList<>(); + + address.getCIAddress().getDeliveryPoint().forEach(deliveryPoint -> { + String deliveryPointString = deliveryPoint.getCharacterString().getValue().toString(); + deliveryPoints.add(deliveryPointString != null ? deliveryPointString : ""); + }); + + if(!deliveryPoints.isEmpty()) { + addressItem.setDeliveryPoint(deliveryPoints); + } + + CharacterStringPropertyType cityString = address.getCIAddress().getCity(); + if(cityString != null + && cityString.getCharacterString() != null + && cityString.getCharacterString().getValue() != null) { + + addressItem.setCity(cityString.getCharacterString().getValue().toString()); + } + + CharacterStringPropertyType administrativeAreaString = address.getCIAddress().getAdministrativeArea(); + if(administrativeAreaString != null + && administrativeAreaString.getCharacterString() != null + && administrativeAreaString.getCharacterString().getValue() != null) { + addressItem.setAdministrativeArea(administrativeAreaString.getCharacterString().getValue().toString()); + } + + CharacterStringPropertyType postalCodeString = address.getCIAddress().getPostalCode(); + if(postalCodeString != null + && postalCodeString.getCharacterString() != null + && postalCodeString.getCharacterString().getValue() != null) { + addressItem.setPostalCode(postalCodeString.getCharacterString().getValue().toString()); + } + + CharacterStringPropertyType countryString = address.getCIAddress().getCountry(); + if(countryString != null + && countryString.getCharacterString() != null + && countryString.getCharacterString().getValue() != null) { + addressItem.setCountry(countryString.getCharacterString().getValue().toString()); + } + + return addressItem; + } + + public static String mapContactsEmail(CharacterStringPropertyType electronicMailAddress) { + + if(electronicMailAddress != null + && electronicMailAddress.getCharacterString() != null + && electronicMailAddress.getCharacterString().getValue() != null + && !"".equalsIgnoreCase(electronicMailAddress.getCharacterString().getValue().toString())) { + return electronicMailAddress.getCharacterString().getValue().toString(); + } + else { + return null; + } + } + + public static LinkModel mapContactsOnlineResource(CIOnlineResourcePropertyType2 onlineResource) { + LinkModel onlineResourceItem = LinkModel.builder().build(); + + CharacterStringPropertyType linkString = onlineResource.getCIOnlineResource().getLinkage(); + if(linkString != null + && linkString.getCharacterString() != null + && linkString.getCharacterString().getValue() != null) { + onlineResourceItem.setHref(linkString.getCharacterString().getValue().toString()); + } + + CharacterStringPropertyType resourceNameString = onlineResource.getCIOnlineResource().getName(); + if(resourceNameString != null + && resourceNameString.getCharacterString() != null + && resourceNameString.getCharacterString().getValue() != null) { + onlineResourceItem.setTitle(resourceNameString.getCharacterString().getValue().toString()); + } + + CharacterStringPropertyType linkTypeString = onlineResource.getCIOnlineResource().getProtocol(); + if(linkTypeString != null + && linkTypeString.getCharacterString() != null + && linkTypeString.getCharacterString().getValue() != null) { + onlineResourceItem.setType(linkTypeString.getCharacterString().getValue().toString()); + } + + return onlineResourceItem; + } + + public static ContactsPhoneModel mapContactsPhone(CITelephonePropertyType2 phone) { + ContactsPhoneModel phoneItem = ContactsPhoneModel.builder().build(); + + CharacterStringPropertyType phoneString = phone.getCITelephone().getNumber(); + if(phoneString != null + && phoneString.getCharacterString() != null + && phoneString.getCharacterString().getValue() != null) { + + phoneItem.setValue(phoneString.getCharacterString().getValue().toString()); + } + + CodeListValueType phoneCode = phone.getCITelephone().getNumberType().getCITelephoneTypeCode(); + if(phoneCode != null && phoneCode.getCodeListValue() != null && !phoneCode.getCodeListValue().isEmpty()) { + phoneItem.setRoles(List.of(phoneCode.getCodeListValue())); + } + + return phoneItem; + } + + public static String mapLanguagesCode(MDDataIdentificationType i) { + try { + return i.getDefaultLocale().getPTLocale().getValue().getLanguage().getLanguageCode().getCodeListValue(); + } + catch (NullPointerException e) { + return null; + } + } + + public static List findMDDataIdentificationType(MDMetadataType source) { + // Read the raw XML to understand the structure. + return source.getIdentificationInfo() + .stream() + .filter(f -> f.getAbstractResourceDescription() != null) + .filter(f -> f.getAbstractResourceDescription().getValue() != null) + .filter(f -> f.getAbstractResourceDescription().getValue() instanceof MDDataIdentificationType) + .map(f -> (MDDataIdentificationType)f.getAbstractResourceDescription().getValue()) + .collect(Collectors.toList()); + } + + public static List findMDMetadataScopePropertyType(MDMetadataType source) { + return source.getMetadataScope() + .stream() + .map(MDMetadataScopePropertyType::getMDMetadataScope) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + public static List findMDDistributionType(MDMetadataType source) { + return source.getDistributionInfo() + .stream() + .filter(f -> f.getAbstractDistribution() != null) + .filter(f -> f.getAbstractDistribution().getValue() != null) + .filter(f -> f.getAbstractDistribution().getValue() instanceof MDDistributionType) + .map(f -> (MDDistributionType)f.getAbstractDistribution().getValue()) + .collect(Collectors.toList()); + } + /** + * Look into the CIContact XML and extract related info and return as a Contract object. Please modify this function + * if more fields need to be returned. + * + * + * + * pointOfContact + * + * + * + * + * CSIRO Oceans & Atmosphere - Hobart + * + * + * + * + * + * + * +61 3 6232 5222 + * + * + * + * + * + * + * + * + * + * +61 3 6232 5000 + * + * + * + * + * + * + * + * + * + * GPO Box 1538 + * + * + * Hobart + * + * + * TAS + * + * + * 7001 + * + * + * Australia + * + * + * + * + * + * + * + * + * + * http://www.csiro.au/en/Research/OandA + * + * + * WWW:LINK-1.0-http--link + * + * + * Web address for organisation CSIRO Oceans & Atmosphere - Hobart + * + * + * + * + * + * + * + * + * + * + * +61 3 6232 5222 + * + * + * + * + * + * + * + * + * + * +61 3 6232 5000 + * + * + * + * + * + * + * + * + * + * Castray Esplanade + * + * + * Hobart + * + * + * TAS + * + * + * 7000 + * + * + * Australia + * + * + * + * + * + * + * + * + * + * http://www.csiro.au/en/Research/OandA + * + * + * WWW:LINK-1.0-http--link + * + * + * Web address for organisation CSIRO Oceans & Atmosphere - Hobart + * + * + * + * + * + * + * + * + * CSIRO O&A, Information & Data Centre + * + * + * + * + * + * + * data-requests-hf@csiro.au + * + * + * + * + * + * + * Data Requests + * + * + * + * + * + * + * + * + * @param contacts The CIContactPropertyType2, it will appear in organization or individual contact + * @return A temp object to hold the contact info + */ + public static Optional mapContactInfo(List contacts) { + if(contacts == null) { + return Optional.empty(); + } + else { + Contacts c = Contacts.builder().build(); + contacts.forEach(contact -> { + // Add all address of organization + if (contact.getCIContact() != null && contact.getCIContact().getAddress() != null) { + contact.getCIContact().getAddress().forEach(v -> { + ContactsAddressModel address = MapperUtils.mapContactsAddress(v); + if(!address.isEmpty()) { + c.getAddresses().add(address); + + if (v.getCIAddress() != null && v.getCIAddress().getElectronicMailAddress() != null) { + c.getEmails().addAll( + v.getCIAddress() + .getElectronicMailAddress() + .stream() + .map(MapperUtils::mapContactsEmail) + .filter(Objects::nonNull) + .toList()); + } + } + }); + } + // Add phone number of organization + if (contact.getCIContact() != null && contact.getCIContact().getPhone() != null) { + c.getPhones().addAll(contact.getCIContact().getPhone().stream().map(MapperUtils::mapContactsPhone).toList()); + } + // Online resources + if (contact.getCIContact().getOnlineResource() != null) { + c.getOnlineResources().addAll(contact.getCIContact().getOnlineResource().stream().map(MapperUtils::mapContactsOnlineResource).toList()); + } + }); + + return Optional.of(c); + } + } + +} diff --git a/indexer/src/test/java/au/org/aodn/esindexer/service/IndexerServiceTests.java b/indexer/src/test/java/au/org/aodn/esindexer/service/IndexerServiceTests.java index 9601da6d..a11f4185 100644 --- a/indexer/src/test/java/au/org/aodn/esindexer/service/IndexerServiceTests.java +++ b/indexer/src/test/java/au/org/aodn/esindexer/service/IndexerServiceTests.java @@ -2,6 +2,7 @@ import au.org.aodn.esindexer.BaseTestClass; import au.org.aodn.esindexer.configuration.GeoNetworkSearchTestConfig; +import au.org.aodn.stac.model.StacCollectionModel; import co.elastic.clients.elasticsearch.core.search.Hit; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -9,6 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.ResponseEntity; import org.springframework.test.context.ActiveProfiles; import org.testcontainers.shaded.org.checkerframework.checker.units.qual.A; @@ -140,7 +142,6 @@ public void verifyGetDocumentByUUID() throws IOException { Hit objectNodeHit = indexerService.getDocumentByUUID(uuid); String test = objectNodeHit.source().toPrettyString(); - assertEquals("Stac equals " + uuid, indexerObjectMapper.readTree(expected), indexerObjectMapper.readTree(test)); } finally { @@ -148,7 +149,10 @@ public void verifyGetDocumentByUUID() throws IOException { } } /** - * Some dataset can provide links to logos, this test is use to verify the logo links added correctly to the + * Some dataset can provide links to logos, this test is use to verify the logo links added correctly to the STAC, + * this function is better test with docker image as it need to invoke some additional function where we need to + * verify it works too. + * * @throws IOException - If file not found */ @Test @@ -185,6 +189,7 @@ public void verifyThumbnailLinkAddedOnIndex() throws IOException { Hit objectNodeHit = indexerService.getDocumentByUUID(uuid); String test = objectNodeHit.source().toPrettyString(); + logger.info(test); assertEquals("Stac equals " + uuid, indexerObjectMapper.readTree(expected), indexerObjectMapper.readTree(test)); } finally { diff --git a/indexer/src/test/java/au/org/aodn/esindexer/service/StacCollectionMapperServiceTests.java b/indexer/src/test/java/au/org/aodn/esindexer/service/StacCollectionMapperServiceTests.java new file mode 100644 index 00000000..a999430e --- /dev/null +++ b/indexer/src/test/java/au/org/aodn/esindexer/service/StacCollectionMapperServiceTests.java @@ -0,0 +1,155 @@ +package au.org.aodn.esindexer.service; + +import au.org.aodn.esindexer.utils.JaxbUtils; +import au.org.aodn.metadata.iso19115_3_2018.MDMetadataType; +import au.org.aodn.stac.model.StacCollectionModel; +import co.elastic.clients.elasticsearch.ElasticsearchClient; +import co.elastic.clients.elasticsearch.core.IndexRequest; +import co.elastic.clients.elasticsearch.core.IndexResponse; +import co.elastic.clients.elasticsearch.core.SearchResponse; + +import co.elastic.clients.elasticsearch.core.search.HitsMetadata; +import co.elastic.clients.elasticsearch.core.search.TotalHits; +import co.elastic.clients.json.JsonData; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import jakarta.xml.bind.JAXBException; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; + +import static au.org.aodn.esindexer.BaseTestClass.readResourceFile; +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +/** + * This test case different from the others as it didn't create docker image to test the whole flow. It only mock the + * component for speed testing. + */ +@Slf4j +@SpringBootTest(classes = {StacCollectionMapperServiceImpl.class}) +public class StacCollectionMapperServiceTests { + + protected ObjectMapper objectMapper = new ObjectMapper(); + protected JaxbUtils jaxbUtils = new JaxbUtils<>(MDMetadataType.class); + + @MockBean + protected GeoNetworkServiceImpl geoNetworkResourceService; + + @MockBean + protected ElasticsearchClient portalElasticsearchClient; + + @MockBean + protected ElasticSearchIndexService elasticSearchIndexService; + + @MockBean + protected AodnDiscoveryParameterVocabService aodnDiscoveryParameterVocabService; + + @MockBean + protected RankingService rankingService; + + @Autowired + protected StacCollectionMapperService service; + + protected AtomicReference> lastRequest = new AtomicReference<>(); + + protected IndexerServiceImpl indexerService; + + public StacCollectionMapperServiceTests() throws JAXBException { + } + + @AfterEach + public void cleanUp() { + Mockito.reset( + geoNetworkResourceService, + portalElasticsearchClient, + elasticSearchIndexService, + aodnDiscoveryParameterVocabService + ); + } + + @BeforeEach + public void createIndexerService() throws IOException { + indexerService = new IndexerServiceImpl( + "any-works", + objectMapper, + jaxbUtils, + rankingService, + geoNetworkResourceService, + portalElasticsearchClient, + elasticSearchIndexService, + service, + aodnDiscoveryParameterVocabService + ); + + // Number is 0, pretend fresh elastic instance + when(elasticSearchIndexService.getDocumentsCount(anyString())) + .thenReturn(0L); + + doNothing() + .when(elasticSearchIndexService) + .createIndexFromMappingJSONFile(anyString(), anyString()); + + doAnswer(ans -> { + lastRequest.set(ans.getArgument(0)); + IndexResponse response = Mockito.mock(IndexResponse.class); + + when(response.version()).thenReturn(1L); + when(response.toString()).thenReturn(""); + + return response; + }) + .when(portalElasticsearchClient) + .index(any(IndexRequest.class)); + + doAnswer(ans -> { + SearchResponse response = Mockito.mock(); + HitsMetadata metadata = Mockito.mock(); + TotalHits totalHits = Mockito.mock(); + + when(totalHits.value()).thenReturn(1L); + when(metadata.total()).thenReturn(totalHits); + when(response.hits()).thenReturn(metadata); + + return response; + }) + .when(portalElasticsearchClient) + .search(any(Function.class), eq(ObjectNode.class)); + + // Pretend empty elastic + when(geoNetworkResourceService.isMetadataRecordsCountLessThan(anyInt())) + .thenReturn(Boolean.TRUE); + + when(geoNetworkResourceService.searchRecordBy(anyString())) + .thenReturn(""); + + when(rankingService.evaluateCompleteness(any(StacCollectionModel.class))) + .thenReturn(1); + + } + + @Test + public void verifyPointOfContactCorrect() throws IOException, JAXBException { + // We only index one record, the + String xml = readResourceFile("classpath:canned/sample8.xml"); + String expected = readResourceFile("classpath:canned/sample8_stac.json"); + indexerService.indexMetadata(xml); + + // We use a mock to pretend insert value into Elastic, there we store what is being send to elastic + // and now we can use it to compare expected result. + Map content = objectMapper.readValue(lastRequest.get().document().toString(), Map.class); + String out = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(content); + assertEquals("Stac equals", objectMapper.readTree(expected), objectMapper.readTree(out.strip())); + } +} diff --git a/indexer/src/test/resources/canned/sample4_stac.json b/indexer/src/test/resources/canned/sample4_stac.json index 99f97ff2..804fff45 100644 --- a/indexer/src/test/resources/canned/sample4_stac.json +++ b/indexer/src/test/resources/canned/sample4_stac.json @@ -1,410 +1,255 @@ { - "title": "Ocean acidification historical reconstruction", - "description": "This dataset contains the reconstructed time series of monthly mean aragonite, calcite and pH together with distribution of dissolved inorganic carbon (DIC), total alkalinity (ALK), sea surface temperature and salinity in the Australian region at a 1 degree resolution over the period 1870-2013.", - "extent": { - "bbox": [ - [ - 95.5, - -44.5, - 169.5, - -0.5 - ], - [ - 95.5, - -44.5, - 169.5, - -44.5, - 169.5, - -0.5, - 95.5, - -0.5, - 95.5, - -44.5 - ] - ], - "temporal": [ - [ - "1870-07-16T14:10:44Z", - "2013-06-16T14:00:00Z" - ], - [ - "1870-07-16T14:10:44Z", - "2013-06-16T14:00:00Z" - ] - ] + "title" : "Ocean acidification historical reconstruction", + "description" : "This dataset contains the reconstructed time series of monthly mean aragonite, calcite and pH together with distribution of dissolved inorganic carbon (DIC), total alkalinity (ALK), sea surface temperature and salinity in the Australian region at a 1 degree resolution over the period 1870-2013.", + "extent" : { + "bbox" : [ [ 95.5, -44.5, 169.5, -0.5 ], [ 95.5, -44.5, 169.5, -44.5, 169.5, -0.5, 95.5, -0.5, 95.5, -44.5 ] ], + "temporal" : [ [ "1870-07-16T14:10:44Z", "2013-06-16T14:00:00Z" ], [ "1870-07-16T14:10:44Z", "2013-06-16T14:00:00Z" ] ] }, - "summaries": { - "score": 95, - "status": "completed", - "scope": { - "code": "dataset", - "name": "" - }, - "dataset_group": "sample", - "dataset_provider": "IMOS", - "proj:geometry": { - "coordinates": [ - [ - [ - [ - 95.5, - -44.5 - ], - [ - 169.5, - -44.5 - ], - [ - 169.5, - -0.5 - ], - [ - 95.5, - -0.5 - ], - [ - 95.5, - -44.5 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "temporal": [ - { - "start": "1870-07-16T14:10:44Z", - "end": "2013-06-16T14:00:00Z" - } - ], - "discovery_categories": [ - "alkalinity", - "carbon", - "temperature", - "salinity" - ] + "summaries" : { + "score" : 95, + "status" : "completed", + "scope" : { + "code" : "dataset", + "name" : "" + }, + "dataset_group" : "sample", + "dataset_provider" : "IMOS", + "proj:geometry" : { + "coordinates" : [ [ [ [ 95.5, -44.5 ], [ 169.5, -44.5 ], [ 169.5, -0.5 ], [ 95.5, -0.5 ], [ 95.5, -44.5 ] ] ] ], + "type" : "MultiPolygon" + }, + "temporal" : [ { + "start" : "1870-07-16T14:10:44Z", + "end" : "2013-06-16T14:00:00Z" + } ], + "discovery_categories" : [ "alkalinity", "carbon", "temperature", "salinity" ] }, - "contacts": [ - { - "emails": [ - "Andrew.Lenton@csiro.au" - ], - "addresses": [ - { - "deliveryPoint": [ - "GPO Box 1538" - ], - "country": "Australia", - "city": "Hobart", - "postalCode": "7000", - "administrativeArea": "Tasmania" - } - ], - "roles": "principalInvestigator", - "organization": "CSIRO Oceans and Atmosphere - Hobart", - "name": "Lenton, Andrew", - "phones": [], - "links": [], - "position": "" - }, - { - "emails": [ - "info@aodn.org.au" - ], - "addresses": [ - { - "deliveryPoint": [ - "University of Tasmania", - "Private Bag 110" - ], - "country": "Australia", - "city": "Hobart", - "postalCode": "7001", - "administrativeArea": "Tasmania" - } - ], - "roles": "pointOfContact", - "organization": "Integrated Marine Observing System (IMOS)", - "name": "", - "phones": [ - { - "roles": "voice", - "value": "61 3 6226 7488" - }, - { - "roles": "facsimile", - "value": "61 3 6226 2701" - } - ], - "links": [ - { - "href": "http://imos.org.au/aodn.html", - "title": "Website of the Australian Ocean Data Network (AODN)", - "type": "WWW:LINK-1.0-http--link" - } - ], - "position": "Data Officer" - } - ], - "languages": [ - { - "code": "eng", - "name": "English" - } - ], - "links": [ - { - "href": "http://www.biogeosciences.net/13/1753/2016", - "rel": "self", - "type": "text/html", - "title": "Biogeosciences Journal article" - }, - { - "href": "https://portal.aodn.org.au/search?uuid=7709f541-fc0c-4318-b5b9-9053aa474e0e", - "rel": "self", - "type": "text/html", - "title": "View and download data though the AODN Portal" - }, - { - "href": "http://thredds.aodn.org.au/thredds/dodsC/CSIRO/Climatology/Ocean_Acidification/OA_Reconstruction.nc.html", - "rel": "self", - "type": "text/html", - "title": "NetCDF files via THREDDS catalog" - }, - { - "href": "http://geoserver-123.aodn.org.au/geoserver/ncwms", - "rel": "self", - "type": "", - "title": "csiro_oa_reconstruction_url/SST" - }, - { - "href": "http://geoserver-123.aodn.org.au/geoserver/ncwms", - "rel": "self", - "type": "", - "title": "csiro_oa_reconstruction_url/SSS" - }, - { - "href": "http://geoserver-123.aodn.org.au/geoserver/ncwms", - "rel": "self", - "type": "", - "title": "csiro_oa_reconstruction_url/ALK" - }, - { - "href": "http://geoserver-123.aodn.org.au/geoserver/ncwms", - "rel": "self", - "type": "", - "title": "csiro_oa_reconstruction_url/DIC" - }, - { - "href": "http://geoserver-123.aodn.org.au/geoserver/ncwms", - "rel": "self", - "type": "", - "title": "csiro_oa_reconstruction_url/OMEGA_A" - }, - { - "href": "http://geoserver-123.aodn.org.au/geoserver/ncwms", - "rel": "self", - "type": "", - "title": "csiro_oa_reconstruction_url/OMEGA_C" - }, - { - "href": "http://geoserver-123.aodn.org.au/geoserver/ncwms", - "rel": "self", - "type": "", - "title": "csiro_oa_reconstruction_url/pH_T" - }, - { - "href": "https://processes.aodn.org.au/wps", - "rel": "self", - "type": "", - "title": "csiro_oa_reconstruction_url" - }, - { - "href": "https://help.aodn.org.au/web-services/gogoduck-aggregator/", - "rel": "self", - "type": "text/html", - "title": "GoGoDuck help documentation" - } - ], - "license": "Creative Commons Attribution 4.0 International License", - "providers": [ - { - "name": "Integrated Marine Observing System (IMOS)", - "roles": [ - "distributor" - ], - "url": "http://imos.org.au/aodn.html" - } - ], - "themes": [ - { - "concepts": [ - { - "id": "Oceans | Ocean Temperature | Sea Surface Temperature" - }, - { - "id": "Oceans | Salinity/density | Salinity" - }, - { - "id": "Oceans | Ocean Chemistry | Carbon Dioxide" - }, - { - "id": "Oceans | Ocean Chemistry | Carbonate" - }, - { - "id": "Oceans | Ocean Chemistry | pH" - } - ], - "scheme": "theme", - "description": "GCMD", - "title": "NASA/Global Change Master Directory Earth Science Keywords Version 5.3.8" - }, - { - "concepts": [ - { - "id": "Ocean Biogeochemistry" - }, - { - "id": "pCO2" - } - ], - "scheme": "theme", - "description": "IMOS", - "title": "IMOS Keywords Thesaurus" - }, - { - "concepts": [ - { - "id": "Global / Oceans | Pacific Ocean" - }, - { - "id": "Global / Oceans | Southern Ocean" - }, - { - "id": "Global / Oceans | Indian Ocean" - }, - { - "id": "Marine Features (Australia) | Great Australian Bight, SA/WA" - }, - { - "id": "Marine Features (Australia) | Bass Strait, TAS/VIC" - }, - { - "id": "Regional Seas | Coral Sea" - }, - { - "id": "Regional Seas | Tasman Sea" - }, - { - "id": "Regional Seas | Timor Sea" - }, - { - "id": "Regional Seas | Arafura Sea" - }, - { - "id": "Regional Seas | Banda Sea" - }, - { - "id": "Regional Seas | Java Sea" - }, - { - "id": "Regional Seas | Solomon Sea" - } - ], - "scheme": "place", - "description": "", - "title": "AODN Geographic Extents Vocabulary" - }, - { - "concepts": [ - { - "id": "Countries | Australia" - }, - { - "id": "Countries | Papua New Guinea" - }, - { - "id": "Countries | Indonesia" - }, - { - "id": "Countries | Timor-Leste" - }, - { - "id": "Countries | New Zealand" - }, - { - "id": "States, Territories (Australia) | Western Australia" - }, - { - "id": "States, Territories (Australia) | Queensland" - }, - { - "id": "States, Territories (Australia) | South Australia" - }, - { - "id": "States, Territories (Australia) | Tasmania" - }, - { - "id": "States, Territories (Australia) | Victoria" - }, - { - "id": "States, Territories (Australia) | New South Wales" - }, - { - "id": "States, Territories (Australia) | Northern Territory" - } - ], - "scheme": "place", - "description": "", - "title": "AODN Geographic Extents Vocabulary" - }, - { - "concepts": [ - { - "id": "Temperature of the water body", - "url": "http://vocab.nerc.ac.uk/collection/P01/current/TEMPPR01" - }, - { - "id": "Practical salinity of the water body", - "url": "http://vocab.nerc.ac.uk/collection/P01/current/PSLTZZ01" - }, - { - "id": "Concentration of carbon (total inorganic) per unit mass of the water body", - "url": "http://vocab.aodn.org.au/def/discovery_parameter/entity/1" - }, - { - "id": "Total alkalinity per unit mass of the water body", - "url": "http://vocab.nerc.ac.uk/collection/P01/current/MDMAP014" - }, - { - "id": "Saturation state of aragonite in the water body", - "url": "http://vocab.aodn.org.au/def/discovery_parameter/entity/24" - }, - { - "id": "Saturation state of calcite in the water body", - "url": "http://vocab.aodn.org.au/def/discovery_parameter/entity/25" - }, - { - "id": "pH (total scale) of the water body", - "url": "http://vocab.aodn.org.au/def/discovery_parameter/entity/27" - } - ], - "scheme": "theme", - "description": "", - "title": "AODN Discovery Parameter Vocabulary" - } - ], - "id": "7709f541-fc0c-4318-b5b9-9053aa474e0e", - "record_suggest": { - "title": "Ocean acidification historical reconstruction" + "contacts" : [ { + "roles" : "principalInvestigator", + "organization" : "CSIRO Oceans and Atmosphere - Hobart", + "name" : "Lenton, Andrew", + "position" : "", + "emails" : [ "Andrew.Lenton@csiro.au" ], + "addresses" : [ { + "deliveryPoint" : [ "GPO Box 1538" ], + "city" : "Hobart", + "country" : "Australia", + "postalCode" : "7000", + "administrativeArea" : "Tasmania" + } ], + "phones" : [ ], + "links" : [ ] + }, { + "roles" : "pointOfContact", + "organization" : "Integrated Marine Observing System (IMOS)", + "name" : "", + "position" : "Data Officer", + "emails" : [ "info@aodn.org.au" ], + "addresses" : [ { + "deliveryPoint" : [ "University of Tasmania", "Private Bag 110" ], + "city" : "Hobart", + "country" : "Australia", + "postalCode" : "7001", + "administrativeArea" : "Tasmania" + } ], + "phones" : [ { + "roles" : [ "voice" ], + "value" : "61 3 6226 7488" + }, { + "roles" : [ "facsimile" ], + "value" : "61 3 6226 2701" + } ], + "links" : [ { + "href" : "http://imos.org.au/aodn.html", + "type" : "WWW:LINK-1.0-http--link", + "title" : "Website of the Australian Ocean Data Network (AODN)" + } ] + } ], + "languages" : [ { + "code" : "eng", + "name" : "English" + } ], + "links" : [ { + "href" : "http://www.biogeosciences.net/13/1753/2016", + "rel" : "self", + "type" : "text/html", + "title" : "Biogeosciences Journal article" + }, { + "href" : "https://portal.aodn.org.au/search?uuid=7709f541-fc0c-4318-b5b9-9053aa474e0e", + "rel" : "self", + "type" : "text/html", + "title" : "View and download data though the AODN Portal" + }, { + "href" : "http://thredds.aodn.org.au/thredds/dodsC/CSIRO/Climatology/Ocean_Acidification/OA_Reconstruction.nc.html", + "rel" : "self", + "type" : "text/html", + "title" : "NetCDF files via THREDDS catalog" + }, { + "href" : "http://geoserver-123.aodn.org.au/geoserver/ncwms", + "rel" : "self", + "type" : "", + "title" : "csiro_oa_reconstruction_url/SST" + }, { + "href" : "http://geoserver-123.aodn.org.au/geoserver/ncwms", + "rel" : "self", + "type" : "", + "title" : "csiro_oa_reconstruction_url/SSS" + }, { + "href" : "http://geoserver-123.aodn.org.au/geoserver/ncwms", + "rel" : "self", + "type" : "", + "title" : "csiro_oa_reconstruction_url/ALK" + }, { + "href" : "http://geoserver-123.aodn.org.au/geoserver/ncwms", + "rel" : "self", + "type" : "", + "title" : "csiro_oa_reconstruction_url/DIC" + }, { + "href" : "http://geoserver-123.aodn.org.au/geoserver/ncwms", + "rel" : "self", + "type" : "", + "title" : "csiro_oa_reconstruction_url/OMEGA_A" + }, { + "href" : "http://geoserver-123.aodn.org.au/geoserver/ncwms", + "rel" : "self", + "type" : "", + "title" : "csiro_oa_reconstruction_url/OMEGA_C" + }, { + "href" : "http://geoserver-123.aodn.org.au/geoserver/ncwms", + "rel" : "self", + "type" : "", + "title" : "csiro_oa_reconstruction_url/pH_T" + }, { + "href" : "https://processes.aodn.org.au/wps", + "rel" : "self", + "type" : "", + "title" : "csiro_oa_reconstruction_url" + }, { + "href" : "https://help.aodn.org.au/web-services/gogoduck-aggregator/", + "rel" : "self", + "type" : "text/html", + "title" : "GoGoDuck help documentation" + } ], + "license" : "Creative Commons Attribution 4.0 International License", + "providers" : [ { + "name" : "Integrated Marine Observing System (IMOS)", + "roles" : [ "distributor" ], + "url" : "http://imos.org.au/aodn.html" + } ], + "themes" : [ { + "concepts" : [ { + "id" : "Oceans | Ocean Temperature | Sea Surface Temperature" + }, { + "id" : "Oceans | Salinity/density | Salinity" + }, { + "id" : "Oceans | Ocean Chemistry | Carbon Dioxide" + }, { + "id" : "Oceans | Ocean Chemistry | Carbonate" + }, { + "id" : "Oceans | Ocean Chemistry | pH" + } ], + "scheme" : "theme", + "description" : "GCMD", + "title" : "NASA/Global Change Master Directory Earth Science Keywords Version 5.3.8" + }, { + "concepts" : [ { + "id" : "Ocean Biogeochemistry" + }, { + "id" : "pCO2" + } ], + "scheme" : "theme", + "description" : "IMOS", + "title" : "IMOS Keywords Thesaurus" + }, { + "concepts" : [ { + "id" : "Global / Oceans | Pacific Ocean" + }, { + "id" : "Global / Oceans | Southern Ocean" + }, { + "id" : "Global / Oceans | Indian Ocean" + }, { + "id" : "Marine Features (Australia) | Great Australian Bight, SA/WA" + }, { + "id" : "Marine Features (Australia) | Bass Strait, TAS/VIC" + }, { + "id" : "Regional Seas | Coral Sea" + }, { + "id" : "Regional Seas | Tasman Sea" + }, { + "id" : "Regional Seas | Timor Sea" + }, { + "id" : "Regional Seas | Arafura Sea" + }, { + "id" : "Regional Seas | Banda Sea" + }, { + "id" : "Regional Seas | Java Sea" + }, { + "id" : "Regional Seas | Solomon Sea" + } ], + "scheme" : "place", + "description" : "", + "title" : "AODN Geographic Extents Vocabulary" + }, { + "concepts" : [ { + "id" : "Countries | Australia" + }, { + "id" : "Countries | Papua New Guinea" + }, { + "id" : "Countries | Indonesia" + }, { + "id" : "Countries | Timor-Leste" + }, { + "id" : "Countries | New Zealand" + }, { + "id" : "States, Territories (Australia) | Western Australia" + }, { + "id" : "States, Territories (Australia) | Queensland" + }, { + "id" : "States, Territories (Australia) | South Australia" + }, { + "id" : "States, Territories (Australia) | Tasmania" + }, { + "id" : "States, Territories (Australia) | Victoria" + }, { + "id" : "States, Territories (Australia) | New South Wales" + }, { + "id" : "States, Territories (Australia) | Northern Territory" + } ], + "scheme" : "place", + "description" : "", + "title" : "AODN Geographic Extents Vocabulary" + }, { + "concepts" : [ { + "id" : "Temperature of the water body", + "url" : "http://vocab.nerc.ac.uk/collection/P01/current/TEMPPR01" + }, { + "id" : "Practical salinity of the water body", + "url" : "http://vocab.nerc.ac.uk/collection/P01/current/PSLTZZ01" + }, { + "id" : "Concentration of carbon (total inorganic) per unit mass of the water body", + "url" : "http://vocab.aodn.org.au/def/discovery_parameter/entity/1" + }, { + "id" : "Total alkalinity per unit mass of the water body", + "url" : "http://vocab.nerc.ac.uk/collection/P01/current/MDMAP014" + }, { + "id" : "Saturation state of aragonite in the water body", + "url" : "http://vocab.aodn.org.au/def/discovery_parameter/entity/24" + }, { + "id" : "Saturation state of calcite in the water body", + "url" : "http://vocab.aodn.org.au/def/discovery_parameter/entity/25" + }, { + "id" : "pH (total scale) of the water body", + "url" : "http://vocab.aodn.org.au/def/discovery_parameter/entity/27" + } ], + "scheme" : "theme", + "description" : "", + "title" : "AODN Discovery Parameter Vocabulary" + } ], + "id" : "7709f541-fc0c-4318-b5b9-9053aa474e0e", + "record_suggest" : { + "title" : "Ocean acidification historical reconstruction" }, - "stac_version": "1.0.0", - "type": "Collection", - "stac_extensions": [ - "https://stac-extensions.github.io/scientific/v1.0.0/schema.json", - "https://stac-extensions.github.io/contacts/v0.1.1/schema.json", - "https://stac-extensions.github.io/projection/v1.1.0/schema.json", - "https://stac-extensions.github.io/language/v1.0.0/schema.json", - "https://stac-extensions.github.io/themes/v1.0.0/schema.json" - ] + "type" : "Collection", + "stac_version" : "1.0.0", + "stac_extensions" : [ "https://stac-extensions.github.io/scientific/v1.0.0/schema.json", "https://stac-extensions.github.io/contacts/v0.1.1/schema.json", "https://stac-extensions.github.io/projection/v1.1.0/schema.json", "https://stac-extensions.github.io/language/v1.0.0/schema.json", "https://stac-extensions.github.io/themes/v1.0.0/schema.json" ] } diff --git a/indexer/src/test/resources/canned/sample5_stac.json b/indexer/src/test/resources/canned/sample5_stac.json index 637ab28a..19215d64 100644 --- a/indexer/src/test/resources/canned/sample5_stac.json +++ b/indexer/src/test/resources/canned/sample5_stac.json @@ -24,30 +24,30 @@ } ] }, "contacts" : [ { + "roles" : "pointOfContact", + "organization" : "Integrated Marine Observing System (IMOS)", + "name" : "", + "position" : "Data Officer", "emails" : [ "info@aodn.org.au" ], "addresses" : [ { "deliveryPoint" : [ "University of Tasmania", "Private Bag 110" ], - "country" : "Australia", "city" : "Hobart", + "country" : "Australia", "postalCode" : "7001", "administrativeArea" : "Tasmania" } ], - "roles" : "pointOfContact", - "organization" : "Integrated Marine Observing System (IMOS)", - "name" : "", "phones" : [ { - "roles" : "voice", + "roles" : [ "voice" ], "value" : "61 3 6226 7488" }, { - "roles" : "facsimile", + "roles" : [ "facsimile" ], "value" : "61 3 6226 2107" } ], "links" : [ { "href" : "http://imos.org.au/aodn.html", - "title" : "Website of the Australian Ocean Data Network (AODN)", - "type" : "WWW:LINK-1.0-http--link" - } ], - "position" : "Data Officer" + "type" : "WWW:LINK-1.0-http--link", + "title" : "Website of the Australian Ocean Data Network (AODN)" + } ] } ], "languages" : [ { "code" : "eng", diff --git a/indexer/src/test/resources/canned/sample6_stac.json b/indexer/src/test/resources/canned/sample6_stac.json index ad9d3d97..0f93abdd 100644 --- a/indexer/src/test/resources/canned/sample6_stac.json +++ b/indexer/src/test/resources/canned/sample6_stac.json @@ -24,20 +24,35 @@ "discovery_categories" : [ "ocean biota", "bathymetry", "density", "water pressure", "current", "temperature", "salinity" ] }, "contacts" : [ { - "emails" : [ "data-requests-hf@csiro.au" ], - "addresses" : [ { - "deliveryPoint" : [ ], - "country" : "", - "city" : "", - "postalCode" : "", - "administrativeArea" : "" - } ], "roles" : "custodian", "organization" : "CSIRO Oceans & Atmosphere - Hobart", "name" : "data-requests-hf@csiro.au,", - "phones" : [ ], - "links" : [ ], - "position" : "Data Requests - Information & Data Centre" + "position" : "Data Requests - Information & Data Centre", + "emails" : [ ], + "addresses" : [ { + "deliveryPoint" : [ "GPO Box 1538" ], + "city" : "Hobart", + "country" : "Australia", + "postalCode" : "7001", + "administrativeArea" : "TAS" + }, { + "deliveryPoint" : [ "Castray Esplanade" ], + "city" : "Hobart", + "country" : "Australia", + "postalCode" : "7000", + "administrativeArea" : "TAS" + } ], + "phones" : [ { + "roles" : [ "voice" ], + "value" : "+61 3 6232 5222" + }, { + "roles" : [ "facsimile" ], + "value" : "+61 3 6232 5000" + } ], + "links" : [ { + "href" : "http://www.csiro.au/en/Research/OandA", + "type" : "WWW:LINK-1.0-http--link" + } ] } ], "languages" : [ { "code" : "eng", diff --git a/indexer/src/test/resources/canned/sample8.xml b/indexer/src/test/resources/canned/sample8.xml new file mode 100644 index 00000000..73c1909a --- /dev/null +++ b/indexer/src/test/resources/canned/sample8.xml @@ -0,0 +1,3400 @@ + + + + + + 1880cd63-d0f9-42e0-b073-7082527945f2 + + + urn:uuid + + + + + + + + + + + + + + + + + + + + + + + + processor + + + + + CSIRO/Oceans and Atmosphere + + + + + Data Officer (AR), Hobart + + + + + + + + + + + pointOfContact + + + + + CSIRO Oceans & Atmosphere - Hobart + + + + + + + +61 3 6232 5222 + + + + + + + + + + +61 3 6232 5000 + + + + + + + + + + GPO Box 1538 + + + Hobart + + + TAS + + + 7001 + + + Australia + + + + + + + + + + http://www.csiro.au/en/Research/OandA + + + WWW:LINK-1.0-http--link + + + Web address for organisation CSIRO Oceans & Atmosphere - Hobart + + + + + + + + + + + +61 3 6232 5222 + + + + + + + + + + +61 3 6232 5000 + + + + + + + + + + Castray Esplanade + + + Hobart + + + TAS + + + 7000 + + + Australia + + + + + + + + + + http://www.csiro.au/en/Research/OandA + + + WWW:LINK-1.0-http--link + + + Web address for organisation CSIRO Oceans & Atmosphere - Hobart + + + + + + + + + CSIRO O&A, Information & Data Centre + + + + + + + data-requests-hf@csiro.au + + + + + + + Data Requests + + + + + + + + + + + + + + + + CSIRO + + + + + Roubicek, Andres + + + + + + + + + + + 2015-10-06T00:00:00 + + + creation + + + + + + + 2022-03-04T00:18:20 + + + + + + + + + + ISO 19115-3:2018 + + + + + + + Marine Community Profile + + + + + 2019-05-30 + + + + + + + + 3.0 + + + 2019-05-30T00:00:00 + + + + + + + + + + Marine Community Profile Governance Committee + + + + + + + https://mcp-profile-docs.readthedocs.io/en/stable/ + + + WWW:LINK-1.0-http--related + + + Documentation + + + + + + + + + + + + + + + https://marlin.csiro.au/geonetwork/srv/eng/catalog.search#/metadata/1880cd63-d0f9-42e0-b073-7082527945f2 + + + WWW:LINK-1.0-http--metadata-URL + + + Point of truth URL of this metadata record + + + + + + + + + WGS 84 (EPSG:4326) + + + EPSG + + + 7.9 + + + + + + + + + + + RV Investigator Voyage IN2019_V06 End of Voyage (EOV) Archive + + + IN2019_V06 EOV + + + Tropical observations of atmospheric convection, biogenic emissions, ocean mixing, and processes generating intraseasonal SST variability + + + + + + + This record describes the End of Voyage (EOV) archive from the Marine National Facility (MNF) RV Investigator research voyage IN2019_V06, titled "Tropical observations of atmospheric convection, biogenic emissions, ocean mixing, and processes generating intraseasonal SST variability." The voyage took place from Darwin (NT) to Darwin between October 19 and December 17, 2019 (AEST). + + For further information please refer to the voyage documentation links below. + + Instruments used and data collected include: + Regular measurements: + Acoustic Doppler Current Profiler (ADCP; 75, 150 KHz ), Lowered ADCP (LADCP), Disdrometer, Fisheries echosounder (EK60), Multibeam Echosounder (EM710, EM122), Sub-bottom Profiler (SBP120), Gravimeter, GPS Positioning System, Doppler Velocity Log, Atmospheric Temperature, Humidity, Pressure, Wind and Rain sensors, Photosynthetically Active Radiation (PAR) sensor, Precision Infrared Radiometer (PIR), Precision Spectral Pyranometer (PSP), Nephelometer, pCO2, Condensation Particle Counters (CPC), Cloud Condensation Nuclei counter (CCN), Multiangle Absorption Photometer (MAAP), Starboard and Portside Radiometers, Ozone sensors, Weather Radar, Greenhouse Gas Analysers (Aerodyne, Picarro), Infrared Sea Surface Temperature Autonomous Radiometer (ISAR), Fluorometer, Oxygen optode, Thermosalinographs (TSG), CTD, Hydrochemistry, Expendable Bathythermographs (XBTs). + + Voyage-specific measurements: + AIRBOX (TSI 3772 Condensation Particle Counter (3772CPC), Black Carbon sensor (Aethalometer), Aerosol mass spectrometer (AMS), Chemical Ionisation Mass Spectrometer (CIMS), Cloud Radar (BASTA), Weather Station, Multi-AXis Differential Optical Absorption Spectrometer (MAX-DOAS), mini Micro-Pulse LIDAR (miniMPL), Neutral Cluster Air Ion Spectrometer (NAIS), Radon sensor, Cloud and Aerosol Backscatter Lidar (RMAN), Scanning Mobility Particle Sizers (SMPS), Sonic Anemometer, Greenhouse Gas Analyser (Fourier Transform Infrared (FTIR) spectrometer - Spectronus), Mercury Analyser (Tekran), Gas Chromatograph - Electron Capture Detector (uDirac), Volatility-Hygroscopicity Tandem Differential Mobility Analyser (VH-TDMA)), Radiosondes, Wave-powered Profiler (Wirewalker), Sea State cameras, Triaxus, ECO Triplet, Sound Velocity Profile (SVP). + + The archive for the IN2019_V06 EOV raw data is curated by the CSIRO NCMI Information and Data Centre (IDC) in Hobart, with a permanent archive at the CSIRO Data Access Portal (DAP, https://data.csiro.au/dap/), providing access to participants and processors of the data collected in the voyage. + + All voyage documentation is available electronically to MNF support via the local network. Access to voyage documentation for non-CSIRO participants can be made via NCMI_DataLibrarians@csiro.au. + + + This data was collected on the Marine National Facility (MNF) RV Investigator voyage IN2019_V06. + + + + + + + + + + + + + CSIRO Oceans & Atmosphere - Hobart + + + + + + + +61 3 6232 5222 + + + + + + + + + + +61 3 6232 5000 + + + + + + + + + + GPO Box 1538 + + + Hobart + + + TAS + + + 7001 + + + Australia + + + + + + + + + + http://www.csiro.au/en/Research/OandA + + + WWW:LINK-1.0-http--link + + + Web address for organisation CSIRO Oceans & Atmosphere - Hobart + + + + + + + + + + + +61 3 6232 5222 + + + + + + + + + + +61 3 6232 5000 + + + + + + + + + + Castray Esplanade + + + Hobart + + + TAS + + + 7000 + + + Australia + + + + + + + + + + http://www.csiro.au/en/Research/OandA + + + WWW:LINK-1.0-http--link + + + Web address for organisation CSIRO Oceans & Atmosphere - Hobart + + + + + + + + + CSIRO O&A, Information & Data Centre + + + + + + + data-requests-hf@csiro.au + + + + + + + Data Requests + + + + + + + + + + + + + + + + + + + + + + + + + oceans + + + climatologyMeteorologyAtmosphere + + + + + + + 120.55 + + + 133.45 + + + -14.68 + + + -10.8 + + + + + + + + 2019-10-19 + 2019-12-17 + + + + + + + + + + + + + + + + + https://www.marine.csiro.au/data/trawler/dataset_mapfile.cfm?survey=IN2019_V06&data_type=uwy + + + IN2019_V06 voyage track + + + PNG + + + + + + + Earth Science | Oceans | Salinity/Density | Salinity + + + Earth Science | Atmosphere | Aerosols + + + Earth Science | Oceans | Ocean Temperature | Sea Surface Temperature + + + Earth Science | Atmosphere | Aerosols | Aerosol Particle Properties + + + Earth Science | Oceans | Ocean Circulation | Ocean Currents + + + Earth Science | Atmosphere | Atmospheric Pressure | Surface Pressure + + + Earth Science | Oceans | Bathymetry/Seafloor Topography | Seafloor Topography + + + Earth Science | Atmosphere | Atmospheric Chemistry | Carbon And Hydrocarbon Compounds | Carbon Dioxide + + + Earth Science | Atmosphere | Atmospheric Temperature | Surface Air Temperature + + + Earth Science | Atmosphere | Aerosols | Cloud Condensation Nuclei + + + Earth Science | Atmosphere | Atmospheric Pressure | Atmospheric Pressure Measurements + + + Earth Science | Atmosphere | Atmospheric Radiation + + + Earth Science | Solid Earth | Gravity/Gravitational Field + + + Earth Science | Atmosphere | Atmospheric Winds | Surface Winds + + + Earth Science | Atmosphere | Atmospheric Winds | Surface Winds | Wind Speed/Wind Direction + + + Earth Science | Oceans | Ocean Chemistry | Nutrients + + + Earth Science | Atmosphere | Clouds + + + Earth Science | Oceans | Ocean Waves | Sea State + + + Earth Science | Oceans | Ocean Chemistry | Carbon Dioxide + + + Earth Science Services | Data Analysis And Visualization | Global Positioning Systems + + + Earth Science | Oceans | Ocean Optics | Photosynthetically Active Radiation + + + Earth Science | Oceans | Ocean Chemistry | Oxygen + + + Earth Science | Atmosphere | Precipitation | Rain + + + Earth Science | Agriculture | Agricultural Aquatic Sciences | Fisheries + + + Earth Science | Atmosphere | Atmospheric Chemistry | Oxygen Compounds | Ozone + + + Earth Science | Atmosphere | Aerosols | Particulate Matter + + + Earth Science | Atmosphere | Atmospheric Radiation | Solar Radiation + + + + + + + + GCMD Keywords + + + + + 2014-04-29T00:00:00 + + + + + + + + + + geonetwork.thesaurus.external.theme.gcmd_keywords + + + + + + + + + + + Research Voyage: IN2019_V06 + + + + + + + + CSIRO Survey List + + + + + 2019-06-19T00:00:00 + + + + + + + + + + geonetwork.thesaurus.register.survey.urn:marlin.csiro.au:surveyregister + + + + + + + + + + + Ship: Investigator (RV) + + + + + + + + CSIRO Source List + + + + + 2016-09-23T00:00:00 + + + + + + + + + + geonetwork.thesaurus.register.dataSource.urn:marlin.csiro.au:sourceregister + + + + + + + + + + + Tropical observations of atmospheric convection, biogenic emissions, ocean mixing, and processes generating intraseasonal SST variability + + + RBR Argo CTD testing + + + + + + + + CSIRO Project List + + + + + 2020-01-10T00:00:00 + + + + + + + + + + geonetwork.thesaurus.register.project.urn:marlin.csiro.au:projectregister + + + + + + + + + + + Coastal Waters (Australia) | Northern Territory Coast, NT + + + Regional Seas | Timor Sea + + + Global / Oceans | East Indian Ocean + + + + + + + + AODN Geographic Extent Names + + + + + 2017-02-17T00:00:00 + + + + + + + + + + geonetwork.thesaurus.register.place.urn:aodn.org.au:geographicextents + + + + + + + + + + + Vessel Data: Multibeam Echosounder + + + Vessel Data: ADCP + + + Vessel Data: XBT + + + Vessel Data: undulating CTD + + + Vessel/Station Data: Hydrology + + + Vessel Data: Dissolved Oxygen + + + Vessel Data: Underway + + + Vessel Data: Acoustics (Fisheries) + + + Vessel Data: CTD + + + + + + + + CSIRO Standard Data Types + + + + + 2016-07-24T00:00:00 + + + + + + + + + + geonetwork.thesaurus.register.discipline.urn:marlin.csiro.au:keywords:standardDataType + + + + + + + + + + + ADCP (Acoustic Doppler Current Profiler) + + + LADCP (Lowered Acoustic Doppler Current Profiler) + + + CCN (Cloud Condensation Nuclei Counter) + + + Greenhouse gas analyser - Aerodyne + + + CPC (Condensation Particle Counters) + + + SMPS (Scanning Mobility Particle Sizers) + + + Greenhouse gas analyser - Picarro + + + Radon Detector + + + CTDs (Conductivity-Temperature-Depth Profilers) + + + Gravity meters + + + Disdrometer (Rain Droplet Particle Sizer) + + + Sub-bottom Profiler - SBP120 + + + Fisheries echosounder EK60 + + + Multibeam Echosounder - EM122 + + + CO2 Analysers + + + Multibeam Echosounder - EM710 + + + Fluorometers + + + Undulating CTD - Triaxus + + + MAAP (Multiangle Absorption Photometer) + + + GPS (Global Positioning System) + + + Thermosalinographs + + + Air sampling systems + + + Weather Radars + + + Radiometer + + + XBTs (Expendable Bathythermographs) + + + Meteorological Instruments + + + Ozone monitor + + + Nephelometers + + + Cloud Radars + + + Mass Spectrometers + + + DMA (Differential Mobility Analyser) + + + LIDAR Altimeter + + + + + + + + CSIRO Equipment + + + + + 2018-08-27T00:00:00 + + + + + + + + + + geonetwork.thesaurus.register.equipment.urn:marlin.csiro.au:Equipment + + + + + + + + + + + Marine National Facility + + + + + + + + CSIRO Areas Of Interest + + + + + 2018-08-27T00:00:00 + + + + + + + + + + geonetwork.thesaurus.register.discipline.urn:marlin.csiro.au:keywords:cmarAOI + + + + + + + + + + + Current direction in the water body + + + Current speed in the water body + + + Eastward current velocity in the water body + + + Northward current velocity in the water body + + + Upward current velocity in the water body + + + Practical salinity of the water body + + + Temperature of the water body + + + Pressure (measured variable) in the water body exerted by overlying sea water and any medium above it + + + Pressure (measured variable) in the water body exerted by overlying sea water only + + + Gravity + + + Sub-bottom structure + + + Abundance of biota + + + Biovolume + + + Sea-floor depth below surface of the water body + + + Sea-floor surface hardness + + + Density of the water body + + + + dataParameter + + + + + + research vessel + + + + platform + + + + + + current profilers + + + lowered current profilers + + + CTD + + + gravimeters + + + 2000 Hz top-bandwidth sub-bottom penetrator and mud profiler systems + + + Fish-finder echosounders + + + multi-beam echosounders + + + thermosalinographs + + + bathythermographs + + + + instrument + + + + + + + + + + + https://i.creativecommons.org/l/by/4.0/88x31.png + + + WWW:LINK-1.0-http--related + + + License Graphic + + + + + + + + + Attribution 4.0 + + + + + https://creativecommons.org/licenses/by/4.0/ + + + WWW:LINK-1.0-http--related + + + License Text + + + + + + + Access to the raw (not quality-controlled) voyage data is intended for the collectors and processors of the data obtained in the MNF RV Investigator voyage. Quality-controlled data products will be made available under the MNF CCBY licence. + + + + + + + + + + + + + + + Data captured as at the End of Voyage. + + + + + + + + + + + + + + > + + + + Current direction in the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UABB + Degrees True + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + current profilers + + + + + + + + + + + + + + + + > + + + + Current speed in the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UVAA + Metres per second + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + current profilers + + + + + + + + + + + + + + + + > + + + + Eastward current velocity in the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UVAA + Metres per second + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + current profilers + + + + + + + + + + + + + + + + > + + + + Northward current velocity in the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UVAA + Metres per second + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + current profilers + + + + + + + + + + + + + + + + > + + + + Upward current velocity in the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UVAA + Metres per second + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + current profilers + + + + + + + + + + + + + + + + > + + + + Current direction in the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UABB + Degrees True + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + lowered current profilers + + + + + + + + + + + + + + + + > + + + + Current speed in the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UVAA + Metres per second + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + lowered current profilers + + + + + + + + + + + + + + + + > + + + + Eastward current velocity in the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UVAA + Metres per second + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + lowered current profilers + + + + + + + + + + + + + + + + > + + + + Northward current velocity in the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UVAA + Metres per second + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + lowered current profilers + + + + + + + + + + + + + + + + > + + + + Upward current velocity in the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UVAA + Metres per second + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + lowered current profilers + + + + + + + + + + + + + + + + > + + + + Practical salinity of the water body + + + + + + http://vocab.aodn.org.au/def/unitsofmeasure/entity/481 + Practical Salinity Unit + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + CTD + + + + + + + + + + + + + + + + > + + + + Temperature of the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UPAA + Degrees Celsius + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + CTD + + + + + + + + + + + + + + + + > + + + + Pressure (measured variable) in the water body exerted by overlying sea water and any medium above it + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UPDB + Decibars + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + CTD + + + + + + + + + + + + + + + + > + + + + Pressure (measured variable) in the water body exerted by overlying sea water only + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UPDB + Decibars + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + CTD + + + + + + + + + + + + + + + + > + + + + Gravity + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UGPM/ + MicroGals per metre + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + gravimeters + + + + + + + + + + + + + + + + > + + + + Sub-bottom structure + + + + + + http://resource.geosciml.org/classifier/cgi/geologicunittype/geologic_unit + geologic unit + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + 2000 Hz top-bandwidth sub-bottom penetrator and mud profiler systems + + + + + + + + + + + + + + + + > + + + + Abundance of biota + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UPMM + Number per cubic meter + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + Fish-finder echosounders + + + + + + + + + + + + + + + + > + + + + Biovolume + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/ULIT + Litres + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + Fish-finder echosounders + + + + + + + + + + + + + + + + > + + + + Sea-floor depth below surface of the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/ULAA + Metres + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + Fish-finder echosounders + + + + + + + + + + + + + + + + > + + + + Sea-floor depth below surface of the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/ULAA + Metres + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + multi-beam echosounders + + + + + + + + + + + + + + + + > + + + + Sea-floor surface hardness + + + + + + http://resource.geosciml.org/classifier/cgi/geologicunittype/geologic_unit + geologic unit + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + multi-beam echosounders + + + + + + + + + + + + + + + + > + + + + Density of the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UKMC + Kilograms per cubic metre + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + multi-beam echosounders + + + + + + + + + + + + + + + + > + + + + Sea-floor depth below surface of the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/ULAA + Metres + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + multi-beam echosounders + + + + + + + + + + + + + + + + > + + + + Sea-floor surface hardness + + + + + + http://resource.geosciml.org/classifier/cgi/geologicunittype/geologic_unit + geologic unit + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + multi-beam echosounders + + + + + + + + + + + + + + + + > + + + + Density of the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UKMC + Kilograms per cubic metre + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + multi-beam echosounders + + + + + + + + + + + + + + + + > + + + + Practical salinity of the water body + + + + + + http://vocab.aodn.org.au/def/unitsofmeasure/entity/481 + Practical Salinity Unit + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + CTD + + + + + + + + + + + + + + + + > + + + + Temperature of the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UPAA + Degrees Celsius + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + CTD + + + + + + + + + + + + + + + + > + + + + Pressure (measured variable) in the water body exerted by overlying sea water and any medium above it + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UPDB + Decibars + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + CTD + + + + + + + + + + + + + + + + > + + + + Pressure (measured variable) in the water body exerted by overlying sea water only + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UPDB + Decibars + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + CTD + + + + + + + + + + + + + + + + > + + + + Practical salinity of the water body + + + + + + http://vocab.aodn.org.au/def/unitsofmeasure/entity/481 + Practical Salinity Unit + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + thermosalinographs + + + + + + + + + + + + + + + + > + + + + Temperature of the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UPAA + Degrees Celsius + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + thermosalinographs + + + + + + + + + + + + + + + + > + + + + Temperature of the water body + + + + + + http://vocab.nerc.ac.uk/collection/P06/current/UPAA + Degrees Celsius + + + + + + + + + + + + + + + + + + + + + research vessel + + + + + Platform used to capture data + + + + + + + bathythermographs + + + + + + + + + + + + + + + + + + + + + + + + + DIGITAL - Binary + + + + + + + + + + + DIGITAL - Images - PDF + + + + + + + + + + + DIGITAL - Spreadsheets - other + + + + + + + + + + + DIGITAL - Text Documents - ASCII + + + + + + + + + + + DIGITAL - netCDF + + + + + + + + + + + + + + + + + + + + https://www.marine.csiro.au/data/trawler/survey_details.cfm?survey=IN2019_V06 + + + WWW:DOWNLOAD-1.0-http--csiro-oa-app + + + Investigator Survey + + + Link to RV Investigator Survey Information, including voyage plans and summaries + + + + + + + https://www.marine.csiro.au/data/underway/?survey=in2019_v06 + + + WWW:DOWNLOAD-1.0-http--csiro-oa-app + + + Underway Visualisation Tool + + + Link to visualisation tool for Near Real-Time Underway Data + + + + + + + https://doi.org/10.25919/fxwd-kw74 + + + WWW:DOWNLOAD-1.0-http--csiro-dap + + + Data Access Portal (DOI) + + + Link to the CSIRO Data Access Portal + + + + + + + https://ws.data.csiro.au/licences/1061 + + + WWW:LINK-1.0-http--link + + + Data Licensing + + + Link to Data License / Attribution Statements + + + + + + + + + + + https://mnf.csiro.au/ + + + WWW:LINK-1.0-http--link + + + Marine National Facility + + + Link to the Marine National Facility Webpage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UHDAS LADCP: only 150kHz run for leg 2 (no 75kHz). Multibeam echosounders EM710 and SBP120: used infrequently. Microstructure profiler (VMP): did not work, bad data from 1 cast. + + + + + + + + + + + + Original field data. The raw EOV data archive was transferred to the NCMI IDC in Hobart. + + A manifest file for the final archive was generated (in2019_v06_manifest_1.0_rawVoyage_cs.txt). + + Available paper documents are scanned to 400 dpi PDF and stored at the IDC record storage system. ELOG files are generated as csv-formatted files and archived. + + + + + + + + + + + + 37120 + iso19115-3.2018 + 2020-06-22T18:41:16 + 2022-03-04T00:18:20 + n + + <source>932cdea7-b6df-469a-aea6-65a6e52882ce</source> + <uuid>1880cd63-d0f9-42e0-b073-7082527945f2</uuid> + <isHarvested>y</isHarvested> + <popularity>20</popularity> + <rating>0</rating> + <displayOrder>0</displayOrder> + <harvestInfo> + <type>csw</type> + </harvestInfo> + <isPublishedToAll>true</isPublishedToAll> + <view>true</view> + <notify>false</notify> + <download>true</download> + <dynamic>true</dynamic> + <featured>false</featured> + <ownername>admin</ownername> + <groupOwnerName>GUEST</groupOwnerName> + <valid>-1</valid> + <baseUrl>https://catalogue.aodn.org.au:443/geonetwork</baseUrl> + <locService>/srv/en</locService> + </geonet:info> +</mdb:MD_Metadata> diff --git a/indexer/src/test/resources/canned/sample8_stac.json b/indexer/src/test/resources/canned/sample8_stac.json new file mode 100644 index 00000000..c45af197 --- /dev/null +++ b/indexer/src/test/resources/canned/sample8_stac.json @@ -0,0 +1,478 @@ +{ + "title" : "RV Investigator Voyage IN2019_V06 End of Voyage (EOV) Archive", + "description" : "This record describes the End of Voyage (EOV) archive from the Marine National Facility (MNF) RV Investigator research voyage IN2019_V06, titled \"Tropical observations of atmospheric convection, biogenic emissions, ocean mixing, and processes generating intraseasonal SST variability.\" The voyage took place from Darwin (NT) to Darwin between October 19 and December 17, 2019 (AEST).\n\n For further information please refer to the voyage documentation links below.\n\n Instruments used and data collected include:\n Regular measurements:\n Acoustic Doppler Current Profiler (ADCP; 75, 150 KHz ), Lowered ADCP (LADCP), Disdrometer, Fisheries echosounder (EK60), Multibeam Echosounder (EM710, EM122), Sub-bottom Profiler (SBP120), Gravimeter, GPS Positioning System, Doppler Velocity Log, Atmospheric Temperature, Humidity, Pressure, Wind and Rain sensors, Photosynthetically Active Radiation (PAR) sensor, Precision Infrared Radiometer (PIR), Precision Spectral Pyranometer (PSP), Nephelometer, pCO2, Condensation Particle Counters (CPC), Cloud Condensation Nuclei counter (CCN), Multiangle Absorption Photometer (MAAP), Starboard and Portside Radiometers, Ozone sensors, Weather Radar, Greenhouse Gas Analysers (Aerodyne, Picarro), Infrared Sea Surface Temperature Autonomous Radiometer (ISAR), Fluorometer, Oxygen optode, Thermosalinographs (TSG), CTD, Hydrochemistry, Expendable Bathythermographs (XBTs).\n\n Voyage-specific measurements:\n AIRBOX (TSI 3772 Condensation Particle Counter (3772CPC), Black Carbon sensor (Aethalometer), Aerosol mass spectrometer (AMS), Chemical Ionisation Mass Spectrometer (CIMS), Cloud Radar (BASTA), Weather Station, Multi-AXis Differential Optical Absorption Spectrometer (MAX-DOAS), mini Micro-Pulse LIDAR (miniMPL), Neutral Cluster Air Ion Spectrometer (NAIS), Radon sensor, Cloud and Aerosol Backscatter Lidar (RMAN), Scanning Mobility Particle Sizers (SMPS), Sonic Anemometer, Greenhouse Gas Analyser (Fourier Transform Infrared (FTIR) spectrometer - Spectronus), Mercury Analyser (Tekran), Gas Chromatograph - Electron Capture Detector (uDirac), Volatility-Hygroscopicity Tandem Differential Mobility Analyser (VH-TDMA)), Radiosondes, Wave-powered Profiler (Wirewalker), Sea State cameras, Triaxus, ECO Triplet, Sound Velocity Profile (SVP).\n\n The archive for the IN2019_V06 EOV raw data is curated by the CSIRO NCMI Information and Data Centre (IDC) in Hobart, with a permanent archive at the CSIRO Data Access Portal (DAP, https://data.csiro.au/dap/), providing access to participants and processors of the data collected in the voyage.\n\n All voyage documentation is available electronically to MNF support via the local network. Access to voyage documentation for non-CSIRO participants can be made via NCMI_DataLibrarians@csiro.au.", + "extent" : { + "bbox" : [ [ 120.55, -14.68, 133.45, -10.8 ], [ 120.55, -14.68, 133.45, -14.68, 133.45, -10.8, 120.55, -10.8, 120.55, -14.68 ] ], + "temporal" : [ [ "2019-10-18T13:00:00Z", "2019-12-16T13:00:00Z" ], [ "2019-10-18T13:00:00Z", "2019-12-16T13:00:00Z" ] ] + }, + "summaries" : { + "score" : 1, + "status" : "completed", + "scope" : { + "code" : "observed", + "name" : "" + }, + "dataset_group" : null, + "dataset_provider" : null, + "update_frequency" : null, + "proj:geometry" : { + "coordinates" : [ [ [ [ 120.55, -14.68 ], [ 133.45, -14.68 ], [ 133.45, -10.8 ], [ 120.55, -10.8 ], [ 120.55, -14.68 ] ] ] ], + "type" : "MultiPolygon" + }, + "temporal" : [ { + "start" : "2019-10-18T13:00:00Z", + "end" : "2019-12-16T13:00:00Z" + } ], + "discovery_categories" : null + }, + "contacts" : [ { + "roles" : "pointOfContact", + "organization" : "CSIRO Oceans & Atmosphere - Hobart", + "name" : "CSIRO O&A, Information & Data Centre", + "position" : "Data Requests", + "emails" : [ ], + "addresses" : [ { + "deliveryPoint" : [ "GPO Box 1538" ], + "city" : "Hobart", + "country" : "Australia", + "postalCode" : "7001", + "administrativeArea" : "TAS" + }, { + "deliveryPoint" : [ "Castray Esplanade" ], + "city" : "Hobart", + "country" : "Australia", + "postalCode" : "7000", + "administrativeArea" : "TAS" + } ], + "phones" : [ { + "roles" : [ "voice" ], + "value" : "+61 3 6232 5222" + }, { + "roles" : [ "facsimile" ], + "value" : "+61 3 6232 5000" + } ], + "links" : [ { + "href" : "http://www.csiro.au/en/Research/OandA", + "rel" : null, + "type" : "WWW:LINK-1.0-http--link", + "title" : null + } ] + } ], + "languages" : [ { + "code" : "eng", + "name" : "English" + } ], + "links" : [ { + "href" : "https://www.marine.csiro.au/data/trawler/survey_details.cfm?survey=IN2019_V06", + "rel" : "self", + "type" : "", + "title" : "Investigator Survey" + }, { + "href" : "https://www.marine.csiro.au/data/underway/?survey=in2019_v06", + "rel" : "self", + "type" : "", + "title" : "Underway Visualisation Tool" + }, { + "href" : "https://doi.org/10.25919/fxwd-kw74", + "rel" : "self", + "type" : "", + "title" : "Data Access Portal (DOI)" + }, { + "href" : "https://ws.data.csiro.au/licences/1061", + "rel" : "self", + "type" : "text/html", + "title" : "Data Licensing" + }, { + "href" : "https://mnf.csiro.au/", + "rel" : "self", + "type" : "text/html", + "title" : "Marine National Facility" + } ], + "license" : "Attribution 4.0", + "providers" : [ { + "name" : "CSIRO/Oceans and Atmosphere", + "description" : null, + "roles" : [ "processor" ], + "url" : null + }, { + "name" : "CSIRO Oceans & Atmosphere - Hobart", + "description" : null, + "roles" : [ "pointOfContact" ], + "url" : null + }, { + "name" : "CSIRO", + "description" : null, + "roles" : [ "originator" ], + "url" : null + } ], + "themes" : [ { + "concepts" : [ { + "id" : "Earth Science | Oceans | Salinity/Density | Salinity", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/7e95b5fc-1d58-431a-af36-948b29fa870d" + }, { + "id" : "Earth Science | Atmosphere | Aerosols", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/2e5a401b-1507-4f57-82b8-36557c13b154" + }, { + "id" : "Earth Science | Oceans | Ocean Temperature | Sea Surface Temperature", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/bd24a9a9-7d52-4c29-b2a0-6cefd216ae78" + }, { + "id" : "Earth Science | Atmosphere | Aerosols | Aerosol Particle Properties", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/02ea239e-4bca-4fda-ab87-be12c723c30a" + }, { + "id" : "Earth Science | Oceans | Ocean Circulation | Ocean Currents", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/510c5f78-e19e-4ce4-b59a-8937aeb84631" + }, { + "id" : "Earth Science | Atmosphere | Atmospheric Pressure | Surface Pressure", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/b54de5cd-4475-4c7b-acbc-4eb529b9396e" + }, { + "id" : "Earth Science | Oceans | Bathymetry/Seafloor Topography | Seafloor Topography", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/b6b51058-1111-4498-a9ac-e1515270fb27" + }, { + "id" : "Earth Science | Atmosphere | Atmospheric Chemistry | Carbon And Hydrocarbon Compounds | Carbon Dioxide", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/c3b81888-8a39-4b3f-8033-4c077797bcba" + }, { + "id" : "Earth Science | Atmosphere | Atmospheric Temperature | Surface Air Temperature", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/5a7bb095-4d12-4232-bc75-b8e82197cb92" + }, { + "id" : "Earth Science | Atmosphere | Aerosols | Cloud Condensation Nuclei", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/27478148-b4b6-4c89-8829-08d2ee7bfe10" + }, { + "id" : "Earth Science | Atmosphere | Atmospheric Pressure | Atmospheric Pressure Measurements", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/9efbc088-ba8c-4c9c-a458-ad6ad63f4188" + }, { + "id" : "Earth Science | Atmosphere | Atmospheric Radiation", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/4ad0c52d-6449-48ff-8678-adc6b2cebcb7" + }, { + "id" : "Earth Science | Solid Earth | Gravity/Gravitational Field", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/221386f6-ef9b-4990-82b3-f990b0fe39fa" + }, { + "id" : "Earth Science | Atmosphere | Atmospheric Winds | Surface Winds", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/10685919-bc01-43e7-901a-b62ac44627f3" + }, { + "id" : "Earth Science | Atmosphere | Atmospheric Winds | Surface Winds | Wind Speed/Wind Direction", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/a92f49f3-e2ee-4ef4-b064-39311ffb95d3" + }, { + "id" : "Earth Science | Oceans | Ocean Chemistry | Nutrients", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/8dd7c9f0-51d0-4037-b1d0-a2517c1770ad" + }, { + "id" : "Earth Science | Atmosphere | Clouds", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/162e2243-3266-4999-b352-d8a1a9dc82ac" + }, { + "id" : "Earth Science | Oceans | Ocean Waves | Sea State", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/11aca777-8a01-42ce-b076-b3059c3d8cae" + }, { + "id" : "Earth Science | Oceans | Ocean Chemistry | Carbon Dioxide", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/26afa886-4866-4536-be3a-6f9db9aacd97" + }, { + "id" : "Earth Science Services | Data Analysis And Visualization | Global Positioning Systems", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/f082ad51-4ce4-4ffe-be50-6753c4f997ae" + }, { + "id" : "Earth Science | Oceans | Ocean Optics | Photosynthetically Active Radiation", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/b7410899-350a-4443-9430-c7fe1fa3a499" + }, { + "id" : "Earth Science | Oceans | Ocean Chemistry | Oxygen", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/90aa8838-79bd-4b28-b518-8217e863c385" + }, { + "id" : "Earth Science | Atmosphere | Precipitation | Rain", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/09a57dc7-3911-4a65-9f12-b819652b8671" + }, { + "id" : "Earth Science | Agriculture | Agricultural Aquatic Sciences | Fisheries", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/c7112a64-be39-414a-9125-f63ab44ecb5b" + }, { + "id" : "Earth Science | Atmosphere | Atmospheric Chemistry | Oxygen Compounds | Ozone", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/dd316647-9043-40c3-9329-f22f9215fefa" + }, { + "id" : "Earth Science | Atmosphere | Aerosols | Particulate Matter", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/548a3f85-bf22-473b-b641-45c32d9c6a0c" + }, { + "id" : "Earth Science | Atmosphere | Atmospheric Radiation | Solar Radiation", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=external.theme.gcmd_keywords&id=http://gcmdservices.gsfc.nasa.gov/kms/concept/a0f3474e-9a54-4a82-97c4-43864b48df4c" + } ], + "scheme" : "theme", + "description" : "", + "title" : "GCMD Keywords" + }, { + "concepts" : [ { + "id" : "Research Voyage: IN2019_V06", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.survey.urn:marlin.csiro.au:surveyregister&id=urn:marlin.csiro.au:surveyregister:concept:2228" + } ], + "scheme" : "survey", + "description" : "", + "title" : "CSIRO Survey List" + }, { + "concepts" : [ { + "id" : "Ship: Investigator (RV)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.dataSource.urn:marlin.csiro.au:sourceregister&id=urn:marlin.csiro.au:sourceregister:concept:309" + } ], + "scheme" : "dataSource", + "description" : "", + "title" : "CSIRO Source List" + }, { + "concepts" : [ { + "id" : "Tropical observations of atmospheric convection, biogenic emissions, ocean mixing, and processes generating intraseasonal SST variability", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.project.urn:marlin.csiro.au:projectregister&id=urn:marlin.csiro.au:projectregister:concept:2485" + }, { + "id" : "RBR Argo CTD testing", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.project.urn:marlin.csiro.au:projectregister&id=urn:marlin.csiro.au:projectregister:concept:2486" + } ], + "scheme" : "project", + "description" : "", + "title" : "CSIRO Project List" + }, { + "concepts" : [ { + "id" : "Coastal Waters (Australia) | Northern Territory Coast, NT", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.place.urn:aodn.org.au:geographicextents&id=urn:aodn.org.au:geographicextents:concept:1003" + }, { + "id" : "Regional Seas | Timor Sea", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.place.urn:aodn.org.au:geographicextents&id=urn:aodn.org.au:geographicextents:concept:24" + }, { + "id" : "Global / Oceans | East Indian Ocean", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.place.urn:aodn.org.au:geographicextents&id=urn:aodn.org.au:geographicextents:concept:1020" + } ], + "scheme" : "place", + "description" : "", + "title" : "AODN Geographic Extent Names" + }, { + "concepts" : [ { + "id" : "Vessel Data: Multibeam Echosounder", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.discipline.urn:marlin.csiro.au:keywords:standardDataType&id=urn:marlin.csiro.au:keywords:standardDataType:concept:3521" + }, { + "id" : "Vessel Data: ADCP", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.discipline.urn:marlin.csiro.au:keywords:standardDataType&id=urn:marlin.csiro.au:keywords:standardDataType:concept:3510" + }, { + "id" : "Vessel Data: XBT", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.discipline.urn:marlin.csiro.au:keywords:standardDataType&id=urn:marlin.csiro.au:keywords:standardDataType:concept:3515" + }, { + "id" : "Vessel Data: undulating CTD", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.discipline.urn:marlin.csiro.au:keywords:standardDataType&id=urn:marlin.csiro.au:keywords:standardDataType:concept:3522" + }, { + "id" : "Vessel/Station Data: Hydrology", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.discipline.urn:marlin.csiro.au:keywords:standardDataType&id=urn:marlin.csiro.au:keywords:standardDataType:concept:3513" + }, { + "id" : "Vessel Data: Dissolved Oxygen", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.discipline.urn:marlin.csiro.au:keywords:standardDataType&id=urn:marlin.csiro.au:keywords:standardDataType:concept:3512" + }, { + "id" : "Vessel Data: Underway", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.discipline.urn:marlin.csiro.au:keywords:standardDataType&id=urn:marlin.csiro.au:keywords:standardDataType:concept:3514" + }, { + "id" : "Vessel Data: Acoustics (Fisheries)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.discipline.urn:marlin.csiro.au:keywords:standardDataType&id=urn:marlin.csiro.au:keywords:standardDataType:concept:3520" + }, { + "id" : "Vessel Data: CTD", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.discipline.urn:marlin.csiro.au:keywords:standardDataType&id=urn:marlin.csiro.au:keywords:standardDataType:concept:3511" + } ], + "scheme" : "discipline", + "description" : "", + "title" : "CSIRO Standard Data Types" + }, { + "concepts" : [ { + "id" : "ADCP (Acoustic Doppler Current Profiler)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:2" + }, { + "id" : "LADCP (Lowered Acoustic Doppler Current Profiler)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:139" + }, { + "id" : "CCN (Cloud Condensation Nuclei Counter)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:127" + }, { + "id" : "Greenhouse gas analyser - Aerodyne", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:176" + }, { + "id" : "CPC (Condensation Particle Counters)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:126" + }, { + "id" : "SMPS (Scanning Mobility Particle Sizers)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:128" + }, { + "id" : "Greenhouse gas analyser - Picarro", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:177" + }, { + "id" : "Radon Detector", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:172" + }, { + "id" : "CTDs (Conductivity-Temperature-Depth Profilers)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:33" + }, { + "id" : "Gravity meters", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:168" + }, { + "id" : "Disdrometer (Rain Droplet Particle Sizer)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:160" + }, { + "id" : "Sub-bottom Profiler - SBP120", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:164" + }, { + "id" : "Fisheries echosounder EK60", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:141" + }, { + "id" : "Multibeam Echosounder - EM122", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:144" + }, { + "id" : "CO2 Analysers", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:17" + }, { + "id" : "Multibeam Echosounder - EM710", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:142" + }, { + "id" : "Fluorometers", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:47" + }, { + "id" : "Undulating CTD - Triaxus", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:174" + }, { + "id" : "MAAP (Multiangle Absorption Photometer)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:180" + }, { + "id" : "GPS (Global Positioning System)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:167" + }, { + "id" : "Thermosalinographs", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:101" + }, { + "id" : "Air sampling systems", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:179" + }, { + "id" : "Weather Radars", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:162" + }, { + "id" : "Radiometer", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:171" + }, { + "id" : "XBTs (Expendable Bathythermographs)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:21" + }, { + "id" : "Meteorological Instruments", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:61" + }, { + "id" : "Ozone monitor", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:178" + }, { + "id" : "Nephelometers", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:125" + }, { + "id" : "Cloud Radars", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:161" + }, { + "id" : "Mass Spectrometers", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:59" + }, { + "id" : "DMA (Differential Mobility Analyser)", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:132" + }, { + "id" : "LIDAR Altimeter", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.equipment.urn:marlin.csiro.au:Equipment&id=urn:marlin.csiro.au:Equipment:concept:56" + } ], + "scheme" : "equipment", + "description" : "", + "title" : "CSIRO Equipment" + }, { + "concepts" : [ { + "id" : "Marine National Facility", + "url" : "https://marlin.csiro.au/geonetwork/srv/eng/xml.keyword.get?thesaurus=register.discipline.urn:marlin.csiro.au:keywords:cmarAOI&id=urn:marlin.csiro.au:keywords:cmarAOI:concept:3208" + } ], + "scheme" : "discipline", + "description" : "", + "title" : "CSIRO Areas Of Interest" + }, { + "concepts" : [ { + "id" : "Current direction in the water body", + "url" : "http://vocab.nerc.ac.uk/collection/P01/current/LCDAZZ01" + }, { + "id" : "Current speed in the water body", + "url" : "http://vocab.aodn.org.au/def/discovery_parameter/entity/383" + }, { + "id" : "Eastward current velocity in the water body", + "url" : "http://vocab.nerc.ac.uk/collection/P01/current/LCEWZZ01" + }, { + "id" : "Northward current velocity in the water body", + "url" : "http://vocab.nerc.ac.uk/collection/P01/current/LCNSZZ01" + }, { + "id" : "Upward current velocity in the water body", + "url" : "http://vocab.nerc.ac.uk/collection/P01/current/LRZAZZZZ" + }, { + "id" : "Practical salinity of the water body", + "url" : "http://vocab.nerc.ac.uk/collection/P01/current/PSLTZZ01" + }, { + "id" : "Temperature of the water body", + "url" : "http://vocab.nerc.ac.uk/collection/P01/current/TEMPPR01" + }, { + "id" : "Pressure (measured variable) in the water body exerted by overlying sea water and any medium above it", + "url" : "http://vocab.aodn.org.au/def/discovery_parameter/entity/565" + }, { + "id" : "Pressure (measured variable) in the water body exerted by overlying sea water only", + "url" : "http://vocab.aodn.org.au/def/discovery_parameter/entity/566" + }, { + "id" : "Gravity", + "url" : "http://vocab.ndg.nerc.ac.uk/term/P011/667/GRAVFLDX" + }, { + "id" : "Sub-bottom structure", + "url" : "N/A" + }, { + "id" : "Abundance of biota", + "url" : "http://vocab.aodn.org.au/def/discovery_parameter/entity/488" + }, { + "id" : "Biovolume", + "url" : "http://vocab.aodn.org.au/def/discovery_parameter/entity/22" + }, { + "id" : "Sea-floor depth below surface of the water body", + "url" : "http://vocab.aodn.org.au/def/discovery_parameter/entity/574" + }, { + "id" : "Sea-floor surface hardness", + "url" : "N/A" + }, { + "id" : "Density of the water body", + "url" : "http://vocab.aodn.org.au/def/discovery_parameter/entity/401" + } ], + "scheme" : "", + "description" : "", + "title" : "" + }, { + "concepts" : [ { + "id" : "research vessel", + "url" : "http://vocab.nerc.ac.uk/collection/L06/current/31" + } ], + "scheme" : "", + "description" : "", + "title" : "" + }, { + "concepts" : [ { + "id" : "current profilers", + "url" : "http://vocab.nerc.ac.uk/collection/L05/current/115" + }, { + "id" : "lowered current profilers", + "url" : "http://vocab.nerc.ac.uk/collection/L05/current/116/" + }, { + "id" : "CTD", + "url" : "http://vocab.nerc.ac.uk/collection/L05/current/130" + }, { + "id" : "gravimeters", + "url" : "http://vocab.nerc.ac.uk/collection/L05/current/158/" + }, { + "id" : "2000 Hz top-bandwidth sub-bottom penetrator and mud profiler systems", + "url" : "http://vocab.nerc.ac.uk/collection/L05/current/367/" + }, { + "id" : "Fish-finder echosounders", + "url" : "http://vocab.nerc.ac.uk/collection/L05/current/FFES" + }, { + "id" : "multi-beam echosounders", + "url" : "http://vocab.nerc.ac.uk/collection/L05/current/157" + }, { + "id" : "thermosalinographs", + "url" : "http://vocab.nerc.ac.uk/collection/L05/current/133" + }, { + "id" : "bathythermographs", + "url" : "http://vocab.nerc.ac.uk/collection/L05/current/132" + } ], + "scheme" : "", + "description" : "", + "title" : "" + } ], + "id" : "1880cd63-d0f9-42e0-b073-7082527945f2", + "record_suggest" : { + "title" : "RV Investigator Voyage IN2019_V06 End of Voyage (EOV) Archive", + "description" : null + }, + "type" : "Collection", + "stac_version" : "1.0.0", + "stac_extensions" : [ "https://stac-extensions.github.io/scientific/v1.0.0/schema.json", "https://stac-extensions.github.io/contacts/v0.1.1/schema.json", "https://stac-extensions.github.io/projection/v1.1.0/schema.json", "https://stac-extensions.github.io/language/v1.0.0/schema.json", "https://stac-extensions.github.io/themes/v1.0.0/schema.json" ] +} diff --git a/stacmodel/src/main/java/au/org/aodn/stac/model/ContactsAddressModel.java b/stacmodel/src/main/java/au/org/aodn/stac/model/ContactsAddressModel.java new file mode 100644 index 00000000..b87dac67 --- /dev/null +++ b/stacmodel/src/main/java/au/org/aodn/stac/model/ContactsAddressModel.java @@ -0,0 +1,45 @@ +package au.org.aodn.stac.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Builder; +import lombok.Data; + +import java.util.List; +import java.util.Objects; + +@Data +@Builder +public class ContactsAddressModel { + protected List<String> deliveryPoint; + protected String city; + protected String country; + protected String postalCode; + protected String administrativeArea; + + @JsonIgnore + public boolean isEmpty() { + return (deliveryPoint == null || deliveryPoint.isEmpty()) + && (city == null || city.isEmpty() || city.isBlank()) + && (country == null || country.isEmpty() || country.isBlank()) + && (postalCode == null || postalCode.isEmpty() || postalCode.isBlank()) + && (administrativeArea == null || administrativeArea.isEmpty() || administrativeArea.isBlank()); + } + + @Override + public int hashCode() { + return Objects.hash(deliveryPoint, city, country, postalCode, administrativeArea); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ContactsAddressModel that = (ContactsAddressModel) o; + return Objects.deepEquals(deliveryPoint, that.deliveryPoint) + && Objects.equals(city, that.city) + && Objects.equals(country, that.country) + && Objects.equals(postalCode, that.postalCode) + && Objects.equals(administrativeArea, that.administrativeArea); + } +} diff --git a/stacmodel/src/main/java/au/org/aodn/stac/model/ContactsModel.java b/stacmodel/src/main/java/au/org/aodn/stac/model/ContactsModel.java index 33f01419..0202fece 100644 --- a/stacmodel/src/main/java/au/org/aodn/stac/model/ContactsModel.java +++ b/stacmodel/src/main/java/au/org/aodn/stac/model/ContactsModel.java @@ -2,18 +2,22 @@ import lombok.Builder; import lombok.Data; + +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @Data @Builder public class ContactsModel { - protected List<String> emails; - protected List<Map<String, Object>> addresses; protected String roles; protected String organization; protected String name; - protected List<Map<String, String>> phones; - protected List<Map<String, String>> links; protected String position; + + // LinkedHashSet to retain order and remove duplicate address, the order is good for debug + protected LinkedHashSet<String> emails; + protected LinkedHashSet<ContactsAddressModel> addresses; + protected LinkedHashSet<ContactsPhoneModel> phones; + protected LinkedHashSet<LinkModel> links; } diff --git a/stacmodel/src/main/java/au/org/aodn/stac/model/ContactsPhoneModel.java b/stacmodel/src/main/java/au/org/aodn/stac/model/ContactsPhoneModel.java new file mode 100644 index 00000000..1c2caa45 --- /dev/null +++ b/stacmodel/src/main/java/au/org/aodn/stac/model/ContactsPhoneModel.java @@ -0,0 +1,29 @@ +package au.org.aodn.stac.model; + +import lombok.Builder; +import lombok.Data; + +import java.util.List; +import java.util.Objects; + +@Data +@Builder +public class ContactsPhoneModel { + protected List<String> roles; + protected String value; + + @Override + public int hashCode() { + return Objects.hash(roles, value); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ContactsPhoneModel that = (ContactsPhoneModel)o; + return Objects.deepEquals(roles, that.roles) + && Objects.equals(value, that.value); + } +} diff --git a/stacmodel/src/main/java/au/org/aodn/stac/model/LinkModel.java b/stacmodel/src/main/java/au/org/aodn/stac/model/LinkModel.java index 287ca4c2..c163926e 100644 --- a/stacmodel/src/main/java/au/org/aodn/stac/model/LinkModel.java +++ b/stacmodel/src/main/java/au/org/aodn/stac/model/LinkModel.java @@ -3,6 +3,8 @@ import lombok.Builder; import lombok.Data; +import java.util.Objects; + @Data @Builder public class LinkModel { @@ -10,4 +12,21 @@ public class LinkModel { protected String rel; protected String type; protected String title; + + @Override + public int hashCode() { + return Objects.hash(href, rel, type, title); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + LinkModel that = (LinkModel) o; + return Objects.equals(href, that.href) + && Objects.equals(rel, that.rel) + && Objects.equals(type, that.type) + && Objects.equals(title, that.title); + } }