]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
DRYD-1939: Search > Update AdvancedSearch to Spec (#487)
authorMichael Ritter <mikejritter@users.noreply.github.com>
Tue, 18 Nov 2025 23:43:48 +0000 (16:43 -0700)
committerGitHub <noreply@github.com>
Tue, 18 Nov 2025 23:43:48 +0000 (16:43 -0700)
* Update advanced search xsd to match spec
* Update natural history extension to match stored data
* Add NAGPRA extension xsd
* Create additional classes to map CollectionObject data to the AdvancedSearchListItem fields

24 files changed:
services/advancedsearch/jaxb/pom.xml
services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/AgentModel.java [new file with mode: 0644]
services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/BriefDescriptionListModel.java
services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/ContentConceptListModel.java
services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/FieldCollectionModel.java [new file with mode: 0644]
services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/NAGPRACategoryModel.java [new file with mode: 0644]
services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/ObjectNameListModel.java
services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/ObjectProductionModel.java [new file with mode: 0644]
services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/ResponsibleDepartmentsListModel.java
services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/TaxonModel.java [new file with mode: 0644]
services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/TitleGroupListModel.java
services/advancedsearch/jaxb/src/main/resources/advanced-search_common.xsd
services/advancedsearch/jaxb/src/test/java/org/collectionspace/services/advancedsearch/model/AgentModelTest.java [new file with mode: 0644]
services/advancedsearch/jaxb/src/test/java/org/collectionspace/services/advancedsearch/model/BriefDescriptionListModelTest.java [new file with mode: 0644]
services/advancedsearch/service/src/main/java/org/collectionspace/services/advancedsearch/AdvancedSearch.java
services/advancedsearch/service/src/main/java/org/collectionspace/services/advancedsearch/AdvancedSearchConstants.java
services/advancedsearch/service/src/main/java/org/collectionspace/services/advancedsearch/AdvancedSearchJAXBContext.java
services/advancedsearch/service/src/main/java/org/collectionspace/services/advancedsearch/mapper/CollectionObjectMapper.java [new file with mode: 0644]
services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceClient.java
services/collectionobject/client/src/main/java/org/collectionspace/services/client/CollectionObjectFactory.java
services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java
services/collectionobject/jaxb/src/main/resources/collectionobjects_common.xsd
services/collectionobject/jaxb/src/main/resources/collectionobjects_nagpra.xsd [new file with mode: 0644]
services/collectionobject/jaxb/src/main/resources/collectionobjects_naturalhistory.xsd

index ca9c5f3c07de075d27ef4a152018a3d57aea8e9f..110fcc0bb64f8e2bb309efe402ddaf0c9f6207d3 100644 (file)
       <artifactId>org.collectionspace.services.collectionobject.jaxb</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.collectionspace.services</groupId>
+      <artifactId>org.collectionspace.services.common-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
   </dependencies>
 
   <build>
diff --git a/services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/AgentModel.java b/services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/AgentModel.java
new file mode 100644 (file)
index 0000000..bfab776
--- /dev/null
@@ -0,0 +1,92 @@
+package org.collectionspace.services.advancedsearch.model;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
+import org.collectionspace.services.collectionobject.ObjectProductionOrganizationGroup;
+import org.collectionspace.services.collectionobject.ObjectProductionOrganizationGroupList;
+import org.collectionspace.services.collectionobject.ObjectProductionPeopleGroup;
+import org.collectionspace.services.collectionobject.ObjectProductionPeopleGroupList;
+import org.collectionspace.services.collectionobject.ObjectProductionPersonGroup;
+import org.collectionspace.services.collectionobject.ObjectProductionPersonGroupList;
+
+public class AgentModel {
+
+       public static Optional<AgentWithRole> agent(CollectionobjectsCommon collectionObject) {
+               if (collectionObject == null) {
+                       return Optional.empty();
+               }
+
+               ObjectProductionPersonGroupList persons = collectionObject.getObjectProductionPersonGroupList();
+               ObjectProductionOrganizationGroupList orgs = collectionObject.getObjectProductionOrganizationGroupList();
+               ObjectProductionPeopleGroupList people = collectionObject.getObjectProductionPeopleGroupList();
+               return Stream.<Supplier<AgentWithRole>>of(
+                       () -> personAgent(persons),
+                       () -> orgAgent(orgs),
+                       () -> peopleAgent(people))
+                               .map(Supplier::get)
+                               .filter(Objects::nonNull)
+                               .findFirst();
+       }
+
+       private static AgentWithRole personAgent(ObjectProductionPersonGroupList personGroupList) {
+               AgentWithRole agent = null;
+               if (personGroupList != null && !personGroupList.getObjectProductionPersonGroup().isEmpty()) {
+                       ObjectProductionPersonGroup personGroup = personGroupList.getObjectProductionPersonGroup().get(0);
+                       String person = personGroup.getObjectProductionPerson();
+                       if (person != null && !person.isEmpty()) {
+                               agent = new AgentWithRole(person);
+                               agent.role = personGroup.getObjectProductionPersonRole();
+                       }
+               }
+               return agent;
+       }
+
+       private static AgentWithRole orgAgent(ObjectProductionOrganizationGroupList organizationGroupList) {
+               AgentWithRole agent = null;
+               if (organizationGroupList != null && !organizationGroupList.getObjectProductionOrganizationGroup().isEmpty()) {
+                       ObjectProductionOrganizationGroup orgGroup =
+                               organizationGroupList.getObjectProductionOrganizationGroup().get(0);
+                       String org = orgGroup.getObjectProductionOrganization();
+                       if (org != null && !org.isEmpty()) {
+                               agent = new AgentWithRole(org);
+                               agent.role = orgGroup.getObjectProductionOrganizationRole();
+                       }
+               }
+               return agent;
+       }
+
+       private static AgentWithRole peopleAgent(ObjectProductionPeopleGroupList peopleGroupList) {
+               AgentWithRole agent = null;
+               if (peopleGroupList != null && !peopleGroupList.getObjectProductionPeopleGroup().isEmpty()) {
+                       ObjectProductionPeopleGroup peopleGroup = peopleGroupList.getObjectProductionPeopleGroup().get(0);
+                       String people = peopleGroup.getObjectProductionPeople();
+                       if (people != null && !people.isEmpty()) {
+                               agent = new AgentWithRole(people);
+                               agent.role = peopleGroup.getObjectProductionPeopleRole();
+                       }
+               }
+               return agent;
+       }
+
+       public static class AgentWithRole {
+               private final String agent;
+               private String role;
+
+               public AgentWithRole(final String agent) {
+                       this.agent = agent;
+               }
+
+               public String getAgent() {
+                       return agent;
+               }
+
+               public String getRole() {
+                       return role;
+               }
+       }
+
+}
index 9cf87ccaf7c23ce1c3a5a14f1cb417dfeb9898ea..1216984c198a178d40959589879d9f1e9d444ea8 100644 (file)
@@ -5,22 +5,25 @@ import java.util.List;
 import org.collectionspace.services.collectionobject.BriefDescriptionList;
 
 public class BriefDescriptionListModel {
-       private static int DESCRIPTION_LENGTH = 55;
+       private static final int DESCRIPTION_LENGTH = 255;
+
        public static String briefDescriptionListToDisplayString(BriefDescriptionList bdList) {
                List<String> bds = bdList.getBriefDescription();
-               String returnString = "";
-               // "Display first 55 (?) characters..." from https://docs.google.com/spreadsheets/d/103jyxa2oCtt8U0IQ25xsOyIxqwKvPNXlcCtcjGlT5tQ/edit?gid=0#gid=0
-               // FIXME the above business logic is inadequate because there are numerous brief descriptions
-               if(null != bds) {
-                       if(!bds.isEmpty()) {
-                               // get the 1st 55 characters of the 1st defined brief description if there is one
-                               if(null != bds.get(0)) {
-                                       int length = bds.get(0).length();
-                                       returnString = bds.get(0).substring(0, (length >= DESCRIPTION_LENGTH) ? DESCRIPTION_LENGTH : length);
+               StringBuilder buf = new StringBuilder();
+               if (null != bds) {
+                       if (!bds.isEmpty()) {
+                               // get the 1st 255 characters of the 1st defined brief description if there is one
+                               String description = bds.get(0);
+                               if (null != description) {
+                                       int length = description.length();
+                                       buf.append(description);
+                                       if (length > DESCRIPTION_LENGTH) {
+                                               buf.replace(DESCRIPTION_LENGTH, buf.length(), "...");
+                                       }
                                }
-                               
+
                        }
                }
-               return returnString;
+               return buf.toString();
        }
 }
index 57a50a391e1efb5219795fab39a66c4c6d90cb39..ae45b7ad60980f5a5afb0a4e02e1c0036bc19288 100644 (file)
@@ -1,35 +1,25 @@
 package org.collectionspace.services.advancedsearch.model;
 
-import java.util.ArrayList;
 import java.util.List;
 
-import org.collectionspace.services.collectionobject.ContentConceptList;
+import org.collectionspace.services.advancedsearch.ContentConcepts;
+import org.collectionspace.services.advancedsearch.ObjectFactory;
+import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
 
 public class ContentConceptListModel {
 
-       public static String contentConceptListDisplayString(ContentConceptList conceptList) {
-               List<String> displayConcepts = new ArrayList<String>();
-               if(null != conceptList) {
-                       List<String> concepts = conceptList.getContentConcept();
-                       for (String conceptRefname : concepts) {
-                               displayConcepts.add(displayNameFromRefName(conceptRefname));
+       public static ContentConcepts contentConceptList(CollectionobjectsCommon collectionObject) {
+               ContentConcepts concepts = null;
+               final ObjectFactory objectFactory = new ObjectFactory();
+
+               if (collectionObject != null && collectionObject.getContentConcepts() != null) {
+                       List<String> objectConcepts = collectionObject.getContentConcepts().getContentConcept();
+                       if (!objectConcepts.isEmpty()) {
+                               concepts = objectFactory.createContentConcepts();
+                               concepts.getContentConcept().addAll(objectConcepts);
                        }
                }
 
-               return String.join(",", displayConcepts);
-       }
-
-       private static String displayNameFromRefName(String refname) {
-               // e.g.
-               // urn:cspace:core.collectionspace.org:conceptauthorities:name(concept):item:name(FooConcept1749234493809)'FooConcept'
-               // -> FooConcept
-               // TODO: there is probably code somewhere for doing this
-           String displayName = refname;
-           if(refname.indexOf("'") < refname.lastIndexOf("'")) {
-               displayName = refname.substring(refname.indexOf("'")+1, refname.lastIndexOf("'"));
-           }
-           
-               return displayName;
+               return concepts;
        }
-
 }
diff --git a/services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/FieldCollectionModel.java b/services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/FieldCollectionModel.java
new file mode 100644 (file)
index 0000000..4acfa60
--- /dev/null
@@ -0,0 +1,54 @@
+package org.collectionspace.services.advancedsearch.model;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
+import org.collectionspace.services.collectionobject.StructuredDateGroup;
+
+public class FieldCollectionModel {
+
+       public static String fieldCollectionPlace(CollectionobjectsCommon common) {
+               String fieldCollectionPlace = null;
+               if (common != null && common.getFieldCollectionPlaces() != null) {
+                       List<String> places = common.getFieldCollectionPlaces().getFieldCollectionPlace();
+                       if (!places.isEmpty()) {
+                               fieldCollectionPlace = places.get(0);
+                       }
+               }
+               return fieldCollectionPlace;
+       }
+
+       public static String fieldCollectionSite(CollectionobjectsCommon common) {
+               String fieldCollectionSite = null;
+               if (common != null && common.getFieldCollectionSites() != null) {
+                       List<String> sites = common.getFieldCollectionSites().getFieldCollectionSite();
+                       if (!sites.isEmpty()) {
+                               fieldCollectionSite = sites.get(0);
+                       }
+               }
+               return fieldCollectionSite;
+       }
+
+       public static String fieldCollectionDate(CollectionobjectsCommon common) {
+               String fieldCollectionDate = null;
+               if (common != null && common.getFieldCollectionDateGroup() != null) {
+                       StructuredDateGroup fieldCollectionDateGroup = common.getFieldCollectionDateGroup();
+                       fieldCollectionDate = fieldCollectionDateGroup.getDateDisplayDate();
+               }
+               return fieldCollectionDate;
+       }
+
+
+       public static Optional<String> fieldCollector(CollectionobjectsCommon common) {
+               String fieldCollector = null;
+               if (common != null && common.getFieldCollectors() != null) {
+                       final List<String> fieldCollectors = common.getFieldCollectors().getFieldCollector();
+                       if (!fieldCollectors.isEmpty()) {
+                               fieldCollector = fieldCollectors.get(0);
+                       }
+               }
+
+               return Optional.ofNullable(fieldCollector);
+       }
+}
diff --git a/services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/NAGPRACategoryModel.java b/services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/NAGPRACategoryModel.java
new file mode 100644 (file)
index 0000000..a45a160
--- /dev/null
@@ -0,0 +1,22 @@
+package org.collectionspace.services.advancedsearch.model;
+
+import org.collectionspace.services.advancedsearch.NagpraCategories;
+import org.collectionspace.services.advancedsearch.ObjectFactory;
+import org.collectionspace.services.collectionobject.domain.nagpra.CollectionObjectsNAGPRA;
+
+public class NAGPRACategoryModel {
+
+       public static NagpraCategories napgraCategories(CollectionObjectsNAGPRA nagpra) {
+               final ObjectFactory asObjectFactory = new ObjectFactory();
+               final CollectionObjectsNAGPRA.NagpraCategories objectNAGPRACategories = nagpra.getNagpraCategories();
+
+               NagpraCategories searchCategories = null;
+               if (objectNAGPRACategories != null && !objectNAGPRACategories.getNagpraCategory().isEmpty()) {
+                       searchCategories = asObjectFactory.createNagpraCategories();
+                       searchCategories.getNagpraCategory().addAll(objectNAGPRACategories.getNagpraCategory());
+               }
+
+               return searchCategories;
+       }
+
+}
index a084882a67be68e01604bb292b6adbf7d226908f..09024828d2f233f4db967651b97568bbc78aa6ab 100644 (file)
@@ -2,22 +2,47 @@ package org.collectionspace.services.advancedsearch.model;
 
 import java.util.List;
 
+import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
 import org.collectionspace.services.collectionobject.ObjectNameGroup;
-import org.collectionspace.services.collectionobject.ObjectNameList;
+import org.collectionspace.services.common.api.RefNameUtils;
 
 public class ObjectNameListModel {
-       public static String objectNameListToDisplayString(ObjectNameList onList) {
-               List<ObjectNameGroup> objectNameGroups = onList.getObjectNameGroup();
-               String returnString = "";
-               if(null != objectNameGroups ) {
-                       if(!objectNameGroups.isEmpty()) {
-                               ObjectNameGroup objectNameGroup = objectNameGroups.get(0);
-                               if(null != objectNameGroup.getObjectName()) {
-                                       returnString = objectNameGroup.getObjectName();
+
+       /**
+        * @param collectionObject The CollectionObject Common part
+        * @return The value of the objectNameControlled field
+        */
+       public static String objectNameControlled(final CollectionobjectsCommon collectionObject) {
+               String objectNameControlled = null;
+
+               if (collectionObject != null && collectionObject.getObjectNameList() != null) {
+                       final List<ObjectNameGroup> objectNameGroups = collectionObject.getObjectNameList().getObjectNameGroup();
+                       if (!objectNameGroups.isEmpty()) {
+                               final ObjectNameGroup objectNameGroup = objectNameGroups.get(0);
+                               try {
+                                       objectNameControlled = RefNameUtils.getDisplayName(objectNameGroup.getObjectNameControlled());
+                               } catch (IllegalArgumentException ignored) {
                                }
                        }
                }
-               
-               return returnString;
+
+               return objectNameControlled;
+       }
+
+       /**
+        * @param collectionObject The CollectionObject Common part
+        * @return The value of the objectName field
+        */
+       public static String objectName(final CollectionobjectsCommon collectionObject) {
+               String objectName = null;
+               if (collectionObject!= null && collectionObject.getObjectNameList() != null) {
+                       final List<ObjectNameGroup> objectNameGroups = collectionObject.getObjectNameList().getObjectNameGroup();
+                       if (!objectNameGroups.isEmpty()) {
+                               final ObjectNameGroup objectNameGroup = objectNameGroups.get(0);
+                               objectName = objectNameGroup.getObjectName();
+                       }
+               }
+
+               return objectName;
        }
 }
diff --git a/services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/ObjectProductionModel.java b/services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/ObjectProductionModel.java
new file mode 100644 (file)
index 0000000..9f865ef
--- /dev/null
@@ -0,0 +1,35 @@
+package org.collectionspace.services.advancedsearch.model;
+
+import java.util.List;
+
+import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
+import org.collectionspace.services.collectionobject.ObjectProductionDateGroupList;
+import org.collectionspace.services.collectionobject.ObjectProductionPlaceGroup;
+
+public class ObjectProductionModel {
+
+       public static String objectProductionDate(CollectionobjectsCommon collectionObject) {
+               String date = null;
+               if (collectionObject != null && collectionObject.getObjectProductionDateGroupList() != null) {
+                       ObjectProductionDateGroupList dateGroup = collectionObject.getObjectProductionDateGroupList();
+                       if (!dateGroup.getObjectProductionDateGroup().isEmpty()) {
+                               date = dateGroup.getObjectProductionDateGroup().get(0).getDateDisplayDate();
+                       }
+               }
+               return date;
+       }
+
+       public static String objectProductionPlace(CollectionobjectsCommon collectionObject) {
+               String place = null;
+               if (collectionObject != null && collectionObject.getObjectProductionPlaceGroupList() != null) {
+                       List<ObjectProductionPlaceGroup> placeGroup = collectionObject.getObjectProductionPlaceGroupList()
+                               .getObjectProductionPlaceGroup();
+
+                       if (!placeGroup.isEmpty()) {
+                               place = placeGroup.get(0).getObjectProductionPlace();
+                       }
+               }
+
+               return place;
+       }
+}
index 1c192bc2a6fcf3ed11ab79500dbd284901028182..862742de5a60d22e5975981f6a6ff579c1ae3b60 100644 (file)
@@ -1,34 +1,19 @@
 package org.collectionspace.services.advancedsearch.model;
 
-import java.util.List;
-
-import org.collectionspace.services.advancedsearch.ObjectFactory;
-import org.collectionspace.services.advancedsearch.ResponsibleDepartment;
-import org.collectionspace.services.advancedsearch.ResponsibleDepartmentsList;
+import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
 import org.collectionspace.services.collectionobject.ResponsibleDepartmentList;
 
 public class ResponsibleDepartmentsListModel {
-       private static ObjectFactory objectFactory = new ObjectFactory();
-       public static ResponsibleDepartmentsList responsibleDepartmentListToResponsibleDepartmentsList(ResponsibleDepartmentList rdList) {
-               ResponsibleDepartmentsList responsibleDepartmentList = objectFactory.createResponsibleDepartmentsList();
-               // NOTE "Display all values separated by comma", from https://docs.google.com/spreadsheets/d/103jyxa2oCtt8U0IQ25xsOyIxqwKvPNXlcCtcjGlT5tQ/edit?gid=0#gid=0
-               List<String> responsibleDepartmentNames = rdList.getResponsibleDepartment();
-               if(null != responsibleDepartmentNames) {
-                       for(String responsibleDepartmentName : responsibleDepartmentNames) {
-                               ResponsibleDepartment responsibleDepartment = objectFactory.createResponsibleDepartment();
-                               responsibleDepartment.setName(responsibleDepartmentName);
-                               responsibleDepartmentList.getResponsibleDepartment().add(responsibleDepartment);
-                       }                       
-               }
 
-               return responsibleDepartmentList;
-       }
-       public static String responsibleDepartmentsListDisplayString(ResponsibleDepartmentsList rdl) {
-               String rdlString = "";
-               if (null != rdl && null != rdl.getResponsibleDepartment() && rdl.getResponsibleDepartment().size() > 0) {
-                       ResponsibleDepartment rd = rdl.getResponsibleDepartment().get(0);
-                       rdlString = rd.getName();
+       public static String responsibleDepartmentString(CollectionobjectsCommon collectionObject) {
+               String responsibleDepartment = null;
+               if (collectionObject != null && collectionObject.getResponsibleDepartments() != null) {
+                       ResponsibleDepartmentList responsibleDepartments = collectionObject.getResponsibleDepartments();
+                       if (!responsibleDepartments.getResponsibleDepartment().isEmpty()) {
+                               responsibleDepartment = responsibleDepartments.getResponsibleDepartment().get(0);
+                       }
                }
-               return rdlString;
+               return responsibleDepartment;
        }
+
 }
diff --git a/services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/TaxonModel.java b/services/advancedsearch/jaxb/src/main/java/org/collectionspace/services/advancedsearch/model/TaxonModel.java
new file mode 100644 (file)
index 0000000..1be0f9c
--- /dev/null
@@ -0,0 +1,37 @@
+package org.collectionspace.services.advancedsearch.model;
+
+import java.util.List;
+
+import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
+import org.collectionspace.services.collectionobject.domain.naturalhistory_extension.CollectionobjectsNaturalhistory;
+import org.collectionspace.services.collectionobject.domain.naturalhistory_extension.TaxonomicIdentGroup;
+import org.collectionspace.services.collectionobject.domain.naturalhistory_extension.TaxonomicIdentGroupList;
+
+public class TaxonModel {
+
+       public static String taxon(final CollectionobjectsNaturalhistory naturalHistory) {
+               String taxon = null;
+               if (naturalHistory != null && naturalHistory.getTaxonomicIdentGroupList() != null) {
+                       TaxonomicIdentGroupList taxonomicIdentGroupList = naturalHistory.getTaxonomicIdentGroupList();
+                       List<TaxonomicIdentGroup> taxonomicIdentGroups = taxonomicIdentGroupList.getTaxonomicIdentGroup();
+                       if (!taxonomicIdentGroups.isEmpty()) {
+                               TaxonomicIdentGroup taxonGroup = taxonomicIdentGroups.get(0);
+                               taxon = taxonGroup.getTaxon();
+                       }
+               }
+
+               return taxon;
+       }
+
+       public static String preservationForm(final CollectionobjectsCommon common) {
+               String form = null;
+               if (common != null && common.getForms() != null) {
+                       List<String> forms = common.getForms().getForm();
+                       if (!forms.isEmpty()) {
+                               form = forms.get(0);
+                       }
+               }
+
+               return form;
+       }
+}
index 6b9844d420a98c5f3ccdd7c98a88b770fde2c4cf..7b55a5dade4730ba173c07fafa48d811d92243bf 100644 (file)
@@ -6,20 +6,24 @@ import org.collectionspace.services.collectionobject.TitleGroup;
 import org.collectionspace.services.collectionobject.TitleGroupList;
 
 public class TitleGroupListModel {
+
+       /**
+        * @param tlList The TitleGroupList
+        * @return the value of the title field for the first TitleGroup
+        */
        public static String titleGroupListToDisplayString(TitleGroupList tlList) {
-               String returnString = "";
+               if (tlList == null) {
+                       return null;
+               }
+
+               String title = null;
                List<TitleGroup> titleGroups = tlList.getTitleGroup();
-               // "Title: Display 1st Title OR 1st Controlled Nomenclature combined with Uncontrolled Nomenclature OR 1st Taxon with Preservation Form" from https://docs.google.com/spreadsheets/d/103jyxa2oCtt8U0IQ25xsOyIxqwKvPNXlcCtcjGlT5tQ/edit?gid=0#gid=0
-               // FIXME: we are not fully implementing the above logic below
-               if(null != titleGroups) {
-                       if(!titleGroups.isEmpty()) {
-                               TitleGroup titleGroup = titleGroups.get(0);
-                               if(null != titleGroup.getTitle()) {
-                                       returnString = titleGroup.getTitle();
-                               }
-                       }
+
+               if (!titleGroups.isEmpty() && titleGroups.get(0) != null) {
+                       TitleGroup titleGroup = titleGroups.get(0);
+                       title = titleGroup.getTitle();
                }
 
-               return returnString;
+               return title;
        }
 }
index 7e07e92db2b0ace60a910ef57ae0ca1c707465ea..2ba600497e7d267cf0ba67a99f95a1a52ac19c75 100644 (file)
     </xs:annotation>
   </xs:complexType>
 
-  <xs:complexType name="responsibleDepartment">
+  <xs:complexType name="contentConcepts">
     <xs:sequence>
-      <xs:element name="uri" type="xs:anyURI"/>
-      <xs:element name="csid" type="xs:string"/>
-      <xs:element name="refName" type="xs:string"/>
-      <xs:element name="name" type="xs:string"/>
+      <xs:element name="contentConcept" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
     </xs:sequence>
   </xs:complexType>
-  <xs:complexType name="responsibleDepartmentsList">
+
+  <xs:complexType name="nagpraCategories">
     <xs:sequence>
-      <xs:element name="responsibleDepartment" type="responsibleDepartment" minOccurs="0" maxOccurs="unbounded"/>
+      <xs:element name="nagpraCategory" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
     </xs:sequence>
   </xs:complexType>
 
                   <xs:element name="refName" type="xs:string"/>
                   <xs:element name="blobCsid" type="xs:string"/>
                   <xs:element name="updatedAt" type="xs:dateTime"/>
-                  <xs:element name="objectId" type="xs:string"/>
                   <xs:element name="objectNumber" type="xs:string"/>
-                  <xs:element name="objectName" type="xs:string"/>
                   <xs:element name="title" type="xs:string"/>
                   <xs:element name="computedCurrentLocation" type="xs:string"/>
-                  <xs:element name="responsibleDepartments" type="responsibleDepartmentsList"/>
                   <xs:element name="responsibleDepartment" type="xs:string"/>
-                  <xs:element name="contentConcepts" type="xs:string"/>
                   <xs:element name="briefDescription" type="xs:string"/>
+
+                  <xs:element name="objectName" type="xs:string"/>
+                  <xs:element name="objectNameControlled" type="xs:string"/>
+                  <xs:element name="taxon" type="xs:string"/>
+                  <xs:element name="form" type="xs:string"/>
+                  <xs:element name="agent" type="xs:string"/>
+                  <xs:element name="agentRole" type="xs:string"/>
+                  <xs:element name="fieldCollector" type="xs:string"/>
+                  <xs:element name="fieldCollectorRole" type="xs:string"/>
+
+                  <xs:element name="fieldCollectionDate" type="xs:string"/>
+                  <xs:element name="fieldCollectionPlace" type="xs:string"/>
+                  <xs:element name="fieldCollectionSite" type="xs:string"/>
+                  <xs:element name="objectProductionDate" type="xs:string"/>
+                  <xs:element name="objectProductionPlace" type="xs:string"/>
+
+                  <xs:element name="contentConcepts" type="contentConcepts"/>
+                  <xs:element name="nagpraCategories" type="nagpraCategories"/>
                 </xs:sequence>
               </xs:complexType>
             </xs:element>
diff --git a/services/advancedsearch/jaxb/src/test/java/org/collectionspace/services/advancedsearch/model/AgentModelTest.java b/services/advancedsearch/jaxb/src/test/java/org/collectionspace/services/advancedsearch/model/AgentModelTest.java
new file mode 100644 (file)
index 0000000..6043549
--- /dev/null
@@ -0,0 +1,112 @@
+package org.collectionspace.services.advancedsearch.model;
+
+import java.util.Optional;
+import java.util.UUID;
+
+import org.collectionspace.services.advancedsearch.model.AgentModel.AgentWithRole;
+import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
+import org.collectionspace.services.collectionobject.ObjectFactory;
+import org.collectionspace.services.collectionobject.ObjectProductionOrganizationGroup;
+import org.collectionspace.services.collectionobject.ObjectProductionOrganizationGroupList;
+import org.collectionspace.services.collectionobject.ObjectProductionPeopleGroup;
+import org.collectionspace.services.collectionobject.ObjectProductionPeopleGroupList;
+import org.collectionspace.services.collectionobject.ObjectProductionPersonGroup;
+import org.collectionspace.services.collectionobject.ObjectProductionPersonGroupList;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Basic tests to ensure that the preferred ordering is used for the Agent and Agent Role response data
+ */
+public class AgentModelTest {
+
+    private ObjectFactory objectFactory;
+    private ObjectProductionPersonGroupList personGroupList;
+    private ObjectProductionOrganizationGroupList orgGroupList;
+    private ObjectProductionPeopleGroupList peopleGroupList;
+
+    @BeforeClass
+    public void setup() {
+        objectFactory = new ObjectFactory();
+
+        ObjectProductionPersonGroup personGroup = objectFactory.createObjectProductionPersonGroup();
+        personGroup.setObjectProductionPerson(UUID.randomUUID().toString());
+        personGroup.setObjectProductionPersonRole(UUID.randomUUID().toString());
+        personGroupList = objectFactory.createObjectProductionPersonGroupList();
+        personGroupList.getObjectProductionPersonGroup().add(personGroup);
+
+        ObjectProductionOrganizationGroup orgGroup = objectFactory.createObjectProductionOrganizationGroup();
+        orgGroup.setObjectProductionOrganization(UUID.randomUUID().toString());
+        orgGroup.setObjectProductionOrganizationRole(UUID.randomUUID().toString());
+        orgGroupList = objectFactory.createObjectProductionOrganizationGroupList();
+        orgGroupList.getObjectProductionOrganizationGroup().add(orgGroup);
+
+        ObjectProductionPeopleGroup peopleGroup = objectFactory.createObjectProductionPeopleGroup();
+        peopleGroup.setObjectProductionPeople(UUID.randomUUID().toString());
+        peopleGroup.setObjectProductionPeopleRole(UUID.randomUUID().toString());
+        peopleGroupList = objectFactory.createObjectProductionPeopleGroupList();
+        peopleGroupList.getObjectProductionPeopleGroup().add(peopleGroup);
+    }
+
+    @Test
+    public void testOrderWithProductionPerson() {
+        final ObjectProductionPersonGroup agentGroup = personGroupList.getObjectProductionPersonGroup().get(0);
+        final String expectedAgent = agentGroup.getObjectProductionPerson();
+        final String expectedRole = agentGroup.getObjectProductionPersonRole();
+
+        final CollectionobjectsCommon common = objectFactory.createCollectionobjectsCommon();
+        common.setObjectProductionPersonGroupList(personGroupList);
+        common.setObjectProductionOrganizationGroupList(orgGroupList);
+        common.setObjectProductionPeopleGroupList(peopleGroupList);
+
+        final Optional<AgentWithRole> agentWithRole = AgentModel.agent(common);
+        Assert.assertTrue(agentWithRole.isPresent());
+
+        final AgentWithRole agent = agentWithRole.get();
+        Assert.assertEquals(agent.getAgent(), expectedAgent);
+        Assert.assertEquals(agent.getRole(), expectedRole);
+    }
+
+    @Test
+    public void testOrderWithProductionOrganization() {
+        final ObjectProductionOrganizationGroup agentGroup = orgGroupList.getObjectProductionOrganizationGroup().get(0);
+        final String expectedAgent = agentGroup.getObjectProductionOrganization();
+        final String expectedRole = agentGroup.getObjectProductionOrganizationRole();
+
+        final CollectionobjectsCommon common = objectFactory.createCollectionobjectsCommon();
+        common.setObjectProductionOrganizationGroupList(orgGroupList);
+        common.setObjectProductionPeopleGroupList(peopleGroupList);
+
+        final Optional<AgentWithRole> agentWithRole = AgentModel.agent(common);
+        Assert.assertTrue(agentWithRole.isPresent());
+
+        final AgentWithRole agent = agentWithRole.get();
+        Assert.assertEquals(agent.getAgent(), expectedAgent);
+        Assert.assertEquals(agent.getRole(), expectedRole);
+    }
+
+    @Test
+    public void testOrderWithProductionPeople() {
+        final ObjectProductionPeopleGroup agentGroup = peopleGroupList.getObjectProductionPeopleGroup().get(0);
+        final String expectedAgent = agentGroup.getObjectProductionPeople();
+        final String expectedRole = agentGroup.getObjectProductionPeopleRole();
+
+        final CollectionobjectsCommon common = objectFactory.createCollectionobjectsCommon();
+        common.setObjectProductionPeopleGroupList(peopleGroupList);
+
+        final Optional<AgentWithRole> agentWithRole = AgentModel.agent(common);
+        Assert.assertTrue(agentWithRole.isPresent());
+
+        final AgentWithRole agent = agentWithRole.get();
+        Assert.assertEquals(agent.getAgent(), expectedAgent);
+        Assert.assertEquals(agent.getRole(), expectedRole);
+    }
+
+    @Test
+    public void testAllEmpty() {
+        final CollectionobjectsCommon common = objectFactory.createCollectionobjectsCommon();
+        final Optional<AgentWithRole> agentWithRole = AgentModel.agent(common);
+        Assert.assertFalse(agentWithRole.isPresent());
+    }
+}
\ No newline at end of file
diff --git a/services/advancedsearch/jaxb/src/test/java/org/collectionspace/services/advancedsearch/model/BriefDescriptionListModelTest.java b/services/advancedsearch/jaxb/src/test/java/org/collectionspace/services/advancedsearch/model/BriefDescriptionListModelTest.java
new file mode 100644 (file)
index 0000000..b86f7bf
--- /dev/null
@@ -0,0 +1,36 @@
+package org.collectionspace.services.advancedsearch.model;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.collectionspace.services.collectionobject.BriefDescriptionList;
+import org.collectionspace.services.collectionobject.ObjectFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Test that we truncate the Brief Description when required
+ */
+public class BriefDescriptionListModelTest {
+    private final ObjectFactory objectFactory = new ObjectFactory();
+
+    @Test
+    public void testShortBriefDescription() {
+        final String description = "short description";
+        final BriefDescriptionList briefDescriptionList = objectFactory.createBriefDescriptionList();
+        briefDescriptionList.getBriefDescription().add(description);
+
+        Assert.assertEquals(BriefDescriptionListModel.briefDescriptionListToDisplayString(briefDescriptionList),
+                            description);
+
+    }
+
+    @Test
+    public void testTruncatedBriefDescription() {
+        String longDescription = RandomStringUtils.randomAlphabetic(300);
+        final BriefDescriptionList briefDescriptionList = objectFactory.createBriefDescriptionList();
+        briefDescriptionList.getBriefDescription().add(longDescription);
+
+        String truncated = BriefDescriptionListModel.briefDescriptionListToDisplayString(briefDescriptionList);
+        Assert.assertTrue(longDescription.length() > truncated.length());
+        Assert.assertTrue(truncated.endsWith("..."));
+    }
+}
\ No newline at end of file
index 91856347bcb944150bf5b111dd95d156e1f8bef6..932487746ef87f875e5599d7e7da6e27f6d5cea8 100644 (file)
@@ -1,10 +1,8 @@
 package org.collectionspace.services.advancedsearch;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
@@ -16,21 +14,11 @@ import javax.ws.rs.core.UriInfo;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
 
-import org.collectionspace.collectionspace_core.CollectionSpaceCore;
 import org.collectionspace.services.MediaJAXBSchema;
 import org.collectionspace.services.advancedsearch.AdvancedsearchCommonList.AdvancedsearchListItem;
-import org.collectionspace.services.advancedsearch.model.BriefDescriptionListModel;
-import org.collectionspace.services.advancedsearch.model.ContentConceptListModel;
-import org.collectionspace.services.advancedsearch.model.ObjectNameListModel;
-import org.collectionspace.services.advancedsearch.model.ResponsibleDepartmentsListModel;
-import org.collectionspace.services.advancedsearch.model.TitleGroupListModel;
-import org.collectionspace.services.client.CollectionObjectClient;
-import org.collectionspace.services.client.CollectionSpaceClient;
+import org.collectionspace.services.advancedsearch.mapper.CollectionObjectMapper;
 import org.collectionspace.services.client.IQueryManager;
-import org.collectionspace.services.client.PayloadOutputPart;
-import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.collectionobject.CollectionObjectResource;
-import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
 import org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl;
 import org.collectionspace.services.common.UriInfoWrapper;
 import org.collectionspace.services.common.context.RemoteServiceContextFactory;
@@ -44,7 +32,6 @@ import org.collectionspace.services.nuxeo.client.handler.UnfilteredDocumentModel
 import org.collectionspace.services.relation.RelationsCommonList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
 /**
@@ -55,11 +42,8 @@ import org.w3c.dom.Element;
 @Produces("application/xml")
 public class AdvancedSearch
                extends AbstractCollectionSpaceResourceImpl<AdvancedsearchListItem, AdvancedsearchListItem> {
+       // FIXME: it's not great to hardcode either of these
        private static final String FIELDS_RETURNED = "uri|csid|refName|blobCsid|updatedAt|objectId|objectNumber|objectName|title|computedCurrentLocation|responsibleDepartments|responsibleDepartment|contentConcepts|briefDescription";
-       // FIXME: it's not great to hardcode this here
-       private static final String COMMON_PART_NAME = CollectionObjectClient.SERVICE_NAME
-                                                      + CollectionSpaceClient.PART_LABEL_SEPARATOR
-                                                      + CollectionSpaceClient.PART_COMMON_LABEL;
 
        private final Logger logger = LoggerFactory.getLogger(AdvancedSearch.class);
        private final CollectionObjectResource cor = new CollectionObjectResource();
@@ -86,10 +70,7 @@ public class AdvancedSearch
 
                cor.setDocumentHandlerClass(UnfilteredDocumentModelHandler.class);
                ObjectFactory objectFactory = new ObjectFactory();
-               // the list to return
                AdvancedsearchCommonList resultsList = objectFactory.createAdvancedsearchCommonList();
-               // FIXME: this shouldn't be necessary?
-               resultsList.advancedsearchListItem = new ArrayList<>();
 
                AbstractCommonList abstractCommonList = cor.getList(uriInfo);
                if (!(abstractCommonList instanceof CSDocumentModelList)) {
@@ -105,78 +86,27 @@ public class AdvancedSearch
                        throw new RuntimeException("Unable to create unmarshaller for AdvancedSearch", e);
                }
 
+               final CollectionObjectMapper responseMapper = new CollectionObjectMapper(unmarshaller);
                for (CSDocumentModelResponse response : collectionObjectList.getResponseList()) {
-                       PoxPayloadOut outputPayload = response.getPayload();
-                       PayloadOutputPart corePart = outputPayload.getPart(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA);
-                       PayloadOutputPart commonPart = outputPayload.getPart(COMMON_PART_NAME);
-                       CollectionSpaceCore core;
-                       CollectionobjectsCommon collectionObject;
-
-                       try {
-                               core = (CollectionSpaceCore) unmarshaller.unmarshal((Document) corePart.getBody());
-                               collectionObject = (CollectionobjectsCommon) unmarshaller.unmarshal((Document) commonPart.getBody());
-                       } catch (JAXBException e) {
-                               throw new RuntimeException(e);
-                       }
-
                        String csid = response.getCsid();
                        UriInfoWrapper wrappedUriInfo = new UriInfoWrapper(uriInfo);
                        List<String> blobCsids = findBlobCsids(csid, wrappedUriInfo);
 
-                       AdvancedsearchListItem listItem = objectFactory.createAdvancedsearchCommonListAdvancedsearchListItem();
-                       if (core != null) {
-                               listItem.setCsid(csid);
-                               listItem.setRefName(core.getRefName());
-                               listItem.setUri(core.getUri());
-                               listItem.setUpdatedAt(core.getUpdatedAt());
-                       } else {
-                               logger.warn("advancedsearch: could not find collectionspace_core associated with csid {}", csid);
-                       }
-
-                       if (collectionObject != null) {
-                               listItem.setObjectNumber(collectionObject.getObjectNumber());
-                               listItem.setBriefDescription(BriefDescriptionListModel
-                                       .briefDescriptionListToDisplayString(collectionObject.getBriefDescriptions()));
-                               listItem.setComputedCurrentLocation(collectionObject.getComputedCurrentLocation());
-                               listItem.setObjectName(
-                                       ObjectNameListModel.objectNameListToDisplayString(collectionObject.getObjectNameList()));
-                               listItem.setTitle(
-                                       TitleGroupListModel.titleGroupListToDisplayString(collectionObject.getTitleGroupList()));
-                               ResponsibleDepartmentsList rdl = ResponsibleDepartmentsListModel
-                                       .responsibleDepartmentListToResponsibleDepartmentsList(
-                                               collectionObject.getResponsibleDepartments());
-                               listItem.setResponsibleDepartments(rdl);
-                               listItem.setResponsibleDepartment(
-                                       ResponsibleDepartmentsListModel.responsibleDepartmentsListDisplayString(rdl));
-
-                               listItem.setContentConcepts(
-                                       ContentConceptListModel.contentConceptListDisplayString(collectionObject.getContentConcepts()));
-
-                               // from media resource
-                               if (blobCsids.size() > 0) {
-                                       listItem.setBlobCsid(blobCsids.get(0));
+                       AdvancedsearchListItem listItem = responseMapper.asListItem(response, blobCsids);
+                       if (listItem != null) {
+                               if (markRelated != null) {
+                                       RelationsCommonList relationsList = relations.getRelationForSubject(markRelated, csid, uriInfo);
+                                       listItem.setRelated(!relationsList.getRelationListItem().isEmpty());
                                }
-                               // add the populated item to the results
                                resultsList.getAdvancedsearchListItem().add(listItem);
-                       } else {
-                               logger.warn("advancedsearch: could not find CollectionobjectsCommon associated with csid {}", csid);
-                       }
-
-                       if (markRelated != null) {
-                               RelationsCommonList relationsList = relations.getRelationForSubject(markRelated, csid, uriInfo);
-                               listItem.setRelated(!relationsList.getRelationListItem().isEmpty());
                        }
                }
 
-               // NOTE: I think this is necessary for the front end to know what to do with
-               // what's returned (?)
-               AbstractCommonList abstractList = (AbstractCommonList) resultsList;
-               abstractList.setItemsInPage(collectionObjectList.getItemsInPage());
-               abstractList.setPageNum(collectionObjectList.getPageNum());
-               abstractList.setPageSize(collectionObjectList.getPageSize());
-               abstractList.setTotalItems(collectionObjectList.getTotalItems());
-               // FIXME: is there a way to generate this rather than hardcode it?
-               abstractList.setFieldsReturned(FIELDS_RETURNED);
+               resultsList.setItemsInPage(collectionObjectList.getItemsInPage());
+               resultsList.setPageNum(collectionObjectList.getPageNum());
+               resultsList.setPageSize(collectionObjectList.getPageSize());
+               resultsList.setTotalItems(collectionObjectList.getTotalItems());
+               resultsList.setFieldsReturned(FIELDS_RETURNED);
 
                return resultsList;
        }
index cf5c3265470977bf4d9f5cb13a5acdbf2f7daed9..98d28797787784ff8e5636badc46baf5ad2d6695 100644 (file)
@@ -1,7 +1,7 @@
 package org.collectionspace.services.advancedsearch;
 
 /**
- * Maybe better as an enum type?
+ * Constants for the AdvancedSearch API
  */
 public interface AdvancedSearchConstants {
 
index ae2bd1206b53a689a23f6935cdd289776cb29234..9a1bb24d94ca2054989d1db083e8873d6213d74b 100644 (file)
@@ -5,6 +5,8 @@ import javax.xml.bind.JAXBException;
 
 import org.collectionspace.collectionspace_core.CollectionSpaceCore;
 import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
+import org.collectionspace.services.collectionobject.domain.nagpra.CollectionObjectsNAGPRA;
+import org.collectionspace.services.collectionobject.domain.naturalhistory_extension.CollectionobjectsNaturalhistory;
 
 /**
  * Singleton for the {@link JAXBContext} which the AdvancedSearch will use
@@ -18,7 +20,8 @@ public final class AdvancedSearchJAXBContext {
 
        private AdvancedSearchJAXBContext() {
                try {
-                       jaxbContext = JAXBContext.newInstance(CollectionSpaceCore.class, CollectionobjectsCommon.class);
+                       jaxbContext = JAXBContext.newInstance(CollectionSpaceCore.class, CollectionobjectsCommon.class,
+                                                             CollectionobjectsNaturalhistory.class, CollectionObjectsNAGPRA.class);
                } catch (JAXBException e) {
                        throw new RuntimeException("Unable to create JAXBContext for AdvancedSearch");
                }
diff --git a/services/advancedsearch/service/src/main/java/org/collectionspace/services/advancedsearch/mapper/CollectionObjectMapper.java b/services/advancedsearch/service/src/main/java/org/collectionspace/services/advancedsearch/mapper/CollectionObjectMapper.java
new file mode 100644 (file)
index 0000000..3b83c27
--- /dev/null
@@ -0,0 +1,172 @@
+package org.collectionspace.services.advancedsearch.mapper;
+
+import static org.collectionspace.services.client.CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA;
+import static org.collectionspace.services.client.CollectionSpaceClient.NAGPRA_EXTENSION_NAME;
+import static org.collectionspace.services.client.CollectionSpaceClient.NATURALHISTORY_EXT_EXTENSION_NAME;
+import static org.collectionspace.services.client.CollectionSpaceClient.PART_COMMON_LABEL;
+import static org.collectionspace.services.client.CollectionSpaceClient.PART_LABEL_SEPARATOR;
+
+import java.util.List;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import org.collectionspace.collectionspace_core.CollectionSpaceCore;
+import org.collectionspace.services.advancedsearch.AdvancedsearchCommonList.AdvancedsearchListItem;
+import org.collectionspace.services.advancedsearch.ObjectFactory;
+import org.collectionspace.services.advancedsearch.model.AgentModel;
+import org.collectionspace.services.advancedsearch.model.BriefDescriptionListModel;
+import org.collectionspace.services.advancedsearch.model.ContentConceptListModel;
+import org.collectionspace.services.advancedsearch.model.FieldCollectionModel;
+import org.collectionspace.services.advancedsearch.model.NAGPRACategoryModel;
+import org.collectionspace.services.advancedsearch.model.ObjectNameListModel;
+import org.collectionspace.services.advancedsearch.model.ObjectProductionModel;
+import org.collectionspace.services.advancedsearch.model.ResponsibleDepartmentsListModel;
+import org.collectionspace.services.advancedsearch.model.TaxonModel;
+import org.collectionspace.services.advancedsearch.model.TitleGroupListModel;
+import org.collectionspace.services.client.CollectionObjectClient;
+import org.collectionspace.services.client.PayloadOutputPart;
+import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
+import org.collectionspace.services.collectionobject.domain.nagpra.CollectionObjectsNAGPRA;
+import org.collectionspace.services.collectionobject.domain.naturalhistory_extension.CollectionobjectsNaturalhistory;
+import org.collectionspace.services.nuxeo.client.handler.CSDocumentModelList.CSDocumentModelResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+/**
+ * A class for mapping {@link CSDocumentModelResponse} to {@link AdvancedsearchListItem}.
+ *
+ * @since 8.3.0
+ */
+public class CollectionObjectMapper {
+
+    private static final Logger logger = LoggerFactory.getLogger(CollectionObjectMapper.class);
+
+    private static final String COMMON_PART_NAME =
+            CollectionObjectClient.SERVICE_NAME + PART_LABEL_SEPARATOR + PART_COMMON_LABEL;
+
+    private static final String NATHIST_PART_NAME =
+            CollectionObjectClient.SERVICE_NAME + PART_LABEL_SEPARATOR + NATURALHISTORY_EXT_EXTENSION_NAME;
+
+    private static final String NAGPRA_PART_NAME =
+            CollectionObjectClient.SERVICE_NAME + PART_LABEL_SEPARATOR + NAGPRA_EXTENSION_NAME;
+
+    private final ObjectFactory objectFactory;
+    private final Unmarshaller unmarshaller;
+
+    public CollectionObjectMapper(Unmarshaller unmarshaller) {
+        this.unmarshaller = unmarshaller;
+        this.objectFactory = new ObjectFactory();
+    }
+
+    /**
+     * Map a {@link CSDocumentModelResponse} to a {@link AdvancedsearchListItem}. This looks at the response for each
+     * of the collectionspace_core, collectionobjects_common, collectionobjects_nagpra, and
+     * collectionobjects_naturalhistory_extension parts and pulls fields out of each based on the search specification.
+     * We don't differentiate between profiles here and instead return everything available for the ui.
+     * <p>
+     * Note that this doesn't handle the {@link AdvancedsearchListItem#setRelated(Boolean)} as that requires access to
+     * the RelationResource. Maybe worth doing through an additional parameter.
+     * @param response The response from the CollectionObjectResource for a single object
+     * @param blobCsids The blobs associated with the object
+     * @return the advanced search list item
+     */
+    public AdvancedsearchListItem asListItem(final CSDocumentModelResponse response, final List<String> blobCsids) {
+        // todo: what makes sense here?
+        if (response == null || response.getPayload() == null) {
+            return objectFactory.createAdvancedsearchCommonListAdvancedsearchListItem();
+        }
+
+        final AdvancedsearchListItem item = objectFactory.createAdvancedsearchCommonListAdvancedsearchListItem();
+
+        final PoxPayloadOut outputPayload = response.getPayload();
+
+        final CollectionSpaceCore core =
+                unmarshall(CollectionSpaceCore.class, COLLECTIONSPACE_CORE_SCHEMA, outputPayload, unmarshaller);
+
+        final CollectionobjectsCommon collectionObject =
+                unmarshall(CollectionobjectsCommon.class, COMMON_PART_NAME, outputPayload, unmarshaller);
+
+        final CollectionObjectsNAGPRA objectsNAGPRA =
+                unmarshall(CollectionObjectsNAGPRA.class, NAGPRA_PART_NAME, outputPayload, unmarshaller);
+
+        final CollectionobjectsNaturalhistory naturalHistory =
+                unmarshall(CollectionobjectsNaturalhistory.class, NATHIST_PART_NAME, outputPayload, unmarshaller);
+
+        final String csid = response.getCsid();
+        item.setCsid(csid);
+        if (core != null) {
+            item.setRefName(core.getRefName());
+            item.setUri(core.getUri());
+            item.setUpdatedAt(core.getUpdatedAt());
+        } else {
+            logger.warn("advancedsearch: could not find collectionspace_core associated with csid {}", csid);
+        }
+
+        if (collectionObject != null) {
+            item.setObjectNumber(collectionObject.getObjectNumber());
+            item.setBriefDescription(BriefDescriptionListModel.briefDescriptionListToDisplayString(
+                    collectionObject.getBriefDescriptions()));
+            item.setComputedCurrentLocation(collectionObject.getComputedCurrentLocation());
+
+            item.setTitle(TitleGroupListModel.titleGroupListToDisplayString(collectionObject.getTitleGroupList()));
+            item.setResponsibleDepartment(
+                    ResponsibleDepartmentsListModel.responsibleDepartmentString(collectionObject));
+
+            item.setObjectName(ObjectNameListModel.objectName(collectionObject));
+            item.setObjectNameControlled(ObjectNameListModel.objectNameControlled(collectionObject));
+
+            item.setContentConcepts(ContentConceptListModel.contentConceptList(collectionObject));
+
+            // Field collection items (place, site, date, collector, role)
+            item.setFieldCollectionPlace(FieldCollectionModel.fieldCollectionPlace(collectionObject));
+            item.setFieldCollectionSite(FieldCollectionModel.fieldCollectionSite(collectionObject));
+            item.setFieldCollectionDate(FieldCollectionModel.fieldCollectionDate(collectionObject));
+            FieldCollectionModel.fieldCollector(collectionObject).ifPresent(collector -> {
+                item.setFieldCollector(collector);
+                item.setFieldCollectorRole("field collector"); // todo: how would we i18n this?
+            });
+
+            // Object Production Information (place, date, agent, agent role)
+            item.setObjectProductionDate(ObjectProductionModel.objectProductionDate(collectionObject));
+            item.setObjectProductionPlace(ObjectProductionModel.objectProductionPlace(collectionObject));
+
+            AgentModel.agent(collectionObject).ifPresent(agent -> {
+                item.setAgent(agent.getAgent());
+                item.setAgentRole(agent.getRole());
+            });
+
+            item.setForm(TaxonModel.preservationForm(collectionObject));
+
+            // from media resource
+            if (blobCsids.size() > 0) {
+                item.setBlobCsid(blobCsids.get(0));
+            }
+        } else {
+            logger.warn("advancedsearch: could not find CollectionobjectsCommon associated with csid {}", csid);
+        }
+
+        if (naturalHistory != null) {
+            item.setTaxon(TaxonModel.taxon(naturalHistory));
+        }
+
+        if (objectsNAGPRA != null) {
+            item.setNagpraCategories(NAGPRACategoryModel.napgraCategories(objectsNAGPRA));
+        }
+
+        return item;
+    }
+
+    public <T> T unmarshall(Class<T> clazz, String namespace, PoxPayloadOut out, Unmarshaller unmarshaller) {
+        PayloadOutputPart part = out.getPart(namespace);
+        if (part == null) {
+            return null;
+        }
+
+        try {
+            return clazz.cast(unmarshaller.unmarshal((Document) part.getBody()));
+        } catch (JAXBException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
index 8324310e871de557336c60d4ae52752b6ced571d..d57aee8ea3e45772ff865abe68e2cd6e6a37533d 100644 (file)
@@ -98,6 +98,7 @@ public interface CollectionSpaceClient<CLT, REQUEST_TYPE, RESPONSE_TYPE, P exten
     //
     // Profile schema name suffixes and extension suffixes
     //
+    public final static String NAGPRA_EXTENSION_NAME = "nagpra";
     public final static String NATURALHISTORY_EXTENSION_NAME = "naturalhistory";
     public final static String NATURALHISTORY_EXT_EXTENSION_NAME = "naturalhistory_extension";
     public final static String VARIABLEMEDIA_EXTENSION_NAME = "variablemedia";
index 2af0aa313b8603c8beb3c2de2a59ecbd62636706..90d8c91c64ed3e9573f59bd0b2c4b990bed8e449 100644 (file)
 
 package org.collectionspace.services.client;
 
-import org.collectionspace.services.client.PayloadOutputPart;
-import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
-import org.collectionspace.services.collectionobject.domain.naturalhistory.CollectionobjectsNaturalhistory;
+import org.collectionspace.services.collectionobject.domain.naturalhistory_extension.CollectionobjectsNaturalhistory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
index 41c6b4c0d11f3d95095a1eb6cbeeaedf1b6b25cc..74e68a241d374795e59df74bad89f72e5b70171b 100644 (file)
@@ -35,7 +35,6 @@ import org.collectionspace.services.client.PayloadOutputPart;
 import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.collectionobject.BriefDescriptionList;
 import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
-import org.collectionspace.services.collectionobject.domain.naturalhistory.CollectionobjectsNaturalhistory;
 import org.collectionspace.services.collectionobject.DimensionSubGroup;
 import org.collectionspace.services.collectionobject.DimensionSubGroupList;
 import org.collectionspace.services.collectionobject.MeasuredPartGroup;
@@ -47,6 +46,7 @@ import org.collectionspace.services.collectionobject.OtherNumber;
 import org.collectionspace.services.collectionobject.ResponsibleDepartmentList;
 import org.collectionspace.services.collectionobject.TitleGroup;
 import org.collectionspace.services.collectionobject.TitleGroupList;
+import org.collectionspace.services.collectionobject.domain.naturalhistory_extension.CollectionobjectsNaturalhistory;
 import org.collectionspace.services.jaxb.AbstractCommonList;
 import org.testng.Assert;
 import org.testng.annotations.Test;
index 89d0a3d6e77b27232c418c8fc04db0077881d047..818ea1ace42a89fb3c8f98d173bacc88d4a1a401 100644 (file)
                 <xs:element name="fieldCollectionMethods" type="fieldCollectionMethodList"/>
                 <xs:element name="fieldCollectionNote" type="xs:string"/>
                 <xs:element name="fieldCollectionNumber" type="xs:string"/>
-                <xs:element name="fieldCollectionPlace" type="xs:string"/>
+                <xs:element name="fieldCollectionPlaces" type="fieldCollectionPlaceList"/>
+                <xs:element name="fieldCollectionSites" type="fieldCollectionSiteList"/>
                 <xs:element name="fieldCollectionSources" type="fieldCollectionSourceList"/>
                 <xs:element name="fieldCollectors" type="fieldCollectorList"/>
                 <xs:element name="fieldColEventNames" type="fieldColEventNameList"/>
             <xs:element name="objectNameSystem" type="xs:string"/>
             <xs:element name="objectNameType" type="xs:string"/>
             <xs:element name="objectNameLanguage" type="xs:string"/>
+            <xs:element name="objectNameControlled" type="xs:string"/>
         </xs:sequence>
     </xs:complexType>
 
         </xs:sequence>
     </xs:complexType>
 
+    <xs:complexType name="fieldCollectionPlaceList">
+        <xs:sequence>
+            <xs:element name="fieldCollectionPlace" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="fieldCollectionSiteList">
+        <xs:sequence>
+            <xs:element name="fieldCollectionSite" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
     <xs:complexType name="fieldCollectorList">
         <xs:sequence>
             <xs:element name="fieldCollector" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
diff --git a/services/collectionobject/jaxb/src/main/resources/collectionobjects_nagpra.xsd b/services/collectionobject/jaxb/src/main/resources/collectionobjects_nagpra.xsd
new file mode 100644 (file)
index 0000000..bfc3b8d
--- /dev/null
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+
+<!--
+    CollectionObject NAGPRA Extension schema (XSD)
+
+    Entity  : CollectionObject
+    Part    : Domain - NAGPRA
+    Used for: JAXB binding between XML and Java objects
+-->
+
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
+           jaxb:version="2.0"
+           xmlns:common="http://collectionspace.org/services/collectionobject"
+           xmlns:nagpra="http://collectionspace.org/services/collectionobject/domain/nagpra"
+           targetNamespace="http://collectionspace.org/services/collectionobject/domain/nagpra"
+           version="0.1"
+>
+
+  <xs:import schemaLocation="collectionobjects_common.xsd"
+             namespace="http://collectionspace.org/services/collectionobject"/>
+
+  <xs:element name="collectionobjects_nagpra">
+    <xs:annotation>
+      <xs:appinfo>
+        <jaxb:class name="CollectionObjectsNAGPRA"/>
+      </xs:appinfo>
+    </xs:annotation>
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="nagpraDetermGroupList" type="nagpra:nagpraDetermGroupList"/>
+
+        <xs:element name="nagpraCategories">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="nagpraCategory" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+
+        <xs:element name="nagpraReportFiledGroupList" type="nagpra:nagpraReportFiledGroupList"/>
+
+        <xs:element name="nagpraInventoryNames">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="nagpraInventoryName" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+        <xs:element name="nagpraCulturalDeterminations">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="nagpraCulturalDetermination" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+        <xs:element name="nagpraNotes">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="nagpraNote" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+        <xs:element name="repatriationNotes">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="repatriationNote" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+        <xs:element name="graveAssocCodes">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="graveAssocCode" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:complexType name="nagpraReportFiledGroupList">
+    <xs:sequence>
+      <xs:element name="nagpraReportFiledGroup" type="nagpra:nagpraReportFiledGroup" minOccurs="0"
+                  maxOccurs="unbounded"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="nagpraReportFiledGroup">
+    <xs:sequence>
+      <xs:element name="nagpraReportFiled" type="xs:boolean"/>
+      <xs:element name="nagpraReportFiledWith" type="xs:string"/>
+      <xs:element name="nagpraReportFiledBy" type="xs:string"/>
+      <xs:element name="nagpraReportFiledDate" type="common:structuredDateGroup"/>
+      <xs:element name="nagpraReportFiledNote" type="xs:string"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="nagpraDetermGroupList">
+    <xs:sequence>
+      <xs:element name="nagpraDetermGroup" type="nagpra:nagpraDetermGroup" minOccurs="0" maxOccurs="unbounded"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <xs:complexType name="nagpraDetermGroup">
+    <xs:sequence>
+      <xs:element name="nagpraDetermCulture" type="xs:string"/>
+      <xs:element name="nagpraDetermType" type="xs:string"/>
+      <xs:element name="nagpraDetermBy" type="xs:string"/>
+      <xs:element name="nagpraDetermNote" type="xs:string"/>
+    </xs:sequence>
+  </xs:complexType>
+</xs:schema>
index 5be1b09c1b0cc49ac14bbc0685723be8a1500cd5..a501ca71e7dffb90d7ae20f617059ad970eba27a 100644 (file)
@@ -2,7 +2,7 @@
 
 <!--
     CollectionObject schema (XSD)
-    
+
     Entity  : CollectionObject
     Part    : Domain - Natural History (example)
     Used for: JAXB binding between XML and Java objects
     $LastChangedDate$
 -->
 
-<xs:schema 
-  xmlns:xs="http://www.w3.org/2001/XMLSchema"
-  xmlns:ns="http://collectionspace.org/services/collectionobject/domain/naturalhistory"
-  xmlns="http://collectionspace.org/services/collectionobject/domain/naturalhistory"
-  targetNamespace="http://collectionspace.org/services/collectionobject/domain/naturalhistory"
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+  xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
+  jaxb:version="2.0"
+  xmlns="http://collectionspace.org/services/collectionobject/domain/naturalhistory_extension"
+  targetNamespace="http://collectionspace.org/services/collectionobject/domain/naturalhistory_extension"
   version="0.1"
 >
-    <!-- collection-object for museum of natural history  -->
-    <xs:element name="collectionobjects_naturalhistory">
-        <xs:complexType>
-                    <xs:sequence>
-
-        <!--
-            <xs:complexType>
-                <xs:sequence>
-                    <xs:element name="nh-string" type="xs:string" />
-                    <xs:element name="nh-int" type="xs:int"/>
-                    <xs:element name="nh-long" type="xs:long"/>
-                    <xs:element name="nh-date" type="xs:dateTime"/>
-                    <xs:element name="nh-note" type="xs:string"/>
-                </xs:sequence>
-            </xs:complexType>
-        -->
-            
+  <!-- collection-object for museum of natural history  -->
+  <xs:element name="collectionobjects_naturalhistory_extension">
+    <!-- keep old class name -->
+    <xs:annotation>
+      <xs:appinfo>
+        <jaxb:class name="CollectionobjectsNaturalhistory"/>
+      </xs:appinfo>
+    </xs:annotation>
+    <xs:complexType>
+      <xs:sequence>
         <xs:element name="fieldLocVerbatim" type="xs:string"/>
         <xs:element name="fieldCollectionDateEarliest" type="xs:string"/>
         <xs:element name="fieldCollectionDateLatest" type="xs:string"/>
         <xs:element name="fieldCollDepthGroupList" type="fieldCollDepthGroupList"/>
         <xs:element name="associatedTaxaGroupList" type="associatedTaxaGroupList"/>
 
-    </xs:sequence>
-   </xs:complexType>
-   </xs:element>
-
-    <xs:complexType name="taxonomicIdentGroupList">
-                <xs:sequence>
-                        <xs:element name="taxonomicIdentGroup" type="taxonomicIdentGroup" minOccurs="0"
-                                maxOccurs="unbounded"/>
-                </xs:sequence>
-        </xs:complexType>
-        <xs:complexType name="taxonomicIdentGroup">
-                <xs:sequence>
-                        <xs:element name="taxon" type="xs:string"/>
-                        <xs:element name="qualifier" type="xs:string"/>
-                        <xs:element name="identBy" type="xs:string"/>
-                        <xs:element name="identDate" type="xs:string"/>
-                        <xs:element name="institution" type="xs:string"/>
-                        <xs:element name="identKind" type="xs:string"/>
-                        <xs:element name="reference" type="xs:string"/>
-                        <xs:element name="refPage" type="xs:string"/>
-                        <xs:element name="notes" type="xs:string"/>
-                 </xs:sequence>
-        </xs:complexType>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
 
-        <xs:complexType name="typeSpecimenGroupList">
-                <xs:sequence>
-                        <xs:element name="typeSpecimenGroup" type="typeSpecimenGroup" minOccurs="0"
-                                maxOccurs="unbounded"/>
-                </xs:sequence>
-        </xs:complexType>
-        <xs:complexType name="typeSpecimenGroup">
-                <xs:sequence>
-                        <xs:element name="kindOfType" type="xs:string"/>
-                        <xs:element name="reference" type="xs:string"/>
-                        <xs:element name="refPage" type="xs:string"/>
-                        <xs:element name="institution" type="xs:string"/>
-                        <xs:element name="institutionType" type="xs:string"/>
-                        <xs:element name="notes" type="xs:string"/>
-                 </xs:sequence>
-        </xs:complexType>
-
-        <xs:complexType name="fieldCollElevationGroupList">
-                <xs:sequence>
-                        <xs:element name="fieldCollElevationGroup" type="fieldCollElevationGroup" minOccurs="0"
-                                maxOccurs="unbounded"/>
-                </xs:sequence>
-        </xs:complexType>
-        <xs:complexType name="fieldCollElevationGroup">
-                <xs:sequence>
-                        <xs:element name="minElevation" type="xs:integer"/>
-                        <xs:element name="maxElevation" type="xs:integer"/>
-                        <xs:element name="units" type="xs:string"/>
-                        <xs:element name="qualifier" type="xs:string"/>
-                        <xs:element name="notes" type="xs:string"/>
-                 </xs:sequence>
-        </xs:complexType>
+  <xs:complexType name="taxonomicIdentGroupList">
+    <xs:sequence>
+      <xs:element name="taxonomicIdentGroup" type="taxonomicIdentGroup" minOccurs="0"
+                  maxOccurs="unbounded"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="taxonomicIdentGroup">
+    <xs:sequence>
+      <xs:element name="taxon" type="xs:string"/>
+      <xs:element name="qualifier" type="xs:string"/>
+      <xs:element name="identBy" type="xs:string"/>
+      <xs:element name="identDate" type="xs:string"/>
+      <xs:element name="institution" type="xs:string"/>
+      <xs:element name="identKind" type="xs:string"/>
+      <xs:element name="reference" type="xs:string"/>
+      <xs:element name="refPage" type="xs:string"/>
+      <xs:element name="notes" type="xs:string"/>
+    </xs:sequence>
+  </xs:complexType>
 
-        <xs:complexType name="fieldCollDepthGroupList">
-                <xs:sequence>
-                        <xs:element name="fieldCollDepthGroup" type="fieldCollDepthGroup" minOccurs="0"
-                                maxOccurs="unbounded"/>
-                </xs:sequence>
-        </xs:complexType>
-        <xs:complexType name="fieldCollDepthGroup">
-                <xs:sequence>
-                        <xs:element name="minDepth" type="xs:integer"/>
-                        <xs:element name="maxDepth" type="xs:integer"/>
-                        <xs:element name="units" type="xs:string"/>
-                        <xs:element name="qualifier" type="xs:string"/>
-                        <xs:element name="notes" type="xs:string"/>
-                 </xs:sequence>
-        </xs:complexType>
+  <xs:complexType name="typeSpecimenGroupList">
+    <xs:sequence>
+      <xs:element name="typeSpecimenGroup" type="typeSpecimenGroup" minOccurs="0"
+                  maxOccurs="unbounded"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="typeSpecimenGroup">
+    <xs:sequence>
+      <xs:element name="kindOfType" type="xs:string"/>
+      <xs:element name="reference" type="xs:string"/>
+      <xs:element name="refPage" type="xs:string"/>
+      <xs:element name="institution" type="xs:string"/>
+      <xs:element name="institutionType" type="xs:string"/>
+      <xs:element name="notes" type="xs:string"/>
+    </xs:sequence>
+  </xs:complexType>
 
-        <xs:complexType name="associatedTaxaGroupList">
-                <xs:sequence>
-                        <xs:element name="associatedTaxaGroup" type="associatedTaxaGroup" minOccurs="0"
-                                maxOccurs="unbounded"/>
-                </xs:sequence>
-        </xs:complexType>
-        <xs:complexType name="associatedTaxaGroup">
-                <xs:sequence>
-                        <xs:element name="taxon" type="xs:string"/>
-                        <xs:element name="commonName" type="xs:integer"/>
-                        <xs:element name="interaction" type="xs:integer"/>
-                 </xs:sequence>
-        </xs:complexType>
+  <xs:complexType name="fieldCollElevationGroupList">
+    <xs:sequence>
+      <xs:element name="fieldCollElevationGroup" type="fieldCollElevationGroup" minOccurs="0"
+                  maxOccurs="unbounded"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="fieldCollElevationGroup">
+    <xs:sequence>
+      <xs:element name="minElevation" type="xs:integer"/>
+      <xs:element name="maxElevation" type="xs:integer"/>
+      <xs:element name="units" type="xs:string"/>
+      <xs:element name="qualifier" type="xs:string"/>
+      <xs:element name="notes" type="xs:string"/>
+    </xs:sequence>
+  </xs:complexType>
 
+  <xs:complexType name="fieldCollDepthGroupList">
+    <xs:sequence>
+      <xs:element name="fieldCollDepthGroup" type="fieldCollDepthGroup" minOccurs="0"
+                  maxOccurs="unbounded"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="fieldCollDepthGroup">
+    <xs:sequence>
+      <xs:element name="minDepth" type="xs:integer"/>
+      <xs:element name="maxDepth" type="xs:integer"/>
+      <xs:element name="units" type="xs:string"/>
+      <xs:element name="qualifier" type="xs:string"/>
+      <xs:element name="notes" type="xs:string"/>
+    </xs:sequence>
+  </xs:complexType>
 
-    
+  <xs:complexType name="associatedTaxaGroupList">
+    <xs:sequence>
+      <xs:element name="associatedTaxaGroup" type="associatedTaxaGroup" minOccurs="0"
+                  maxOccurs="unbounded"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="associatedTaxaGroup">
+    <xs:sequence>
+      <xs:element name="taxon" type="xs:string"/>
+      <xs:element name="commonName" type="xs:integer"/>
+      <xs:element name="interaction" type="xs:integer"/>
+    </xs:sequence>
+  </xs:complexType>
 </xs:schema>