diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 6de3c773c..9987466f3 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -15,11 +15,11 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Docker meta id: meta - uses: docker/metadata-action@v3 + uses: docker/metadata-action@v5 with: # list of Docker images to use as base name for tags images: | @@ -31,19 +31,19 @@ jobs: type=ref,event=tag,suffix=-${{ matrix.chemistry_package }} - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} diff --git a/.github/workflows/trigger-tag.yml b/.github/workflows/trigger-tag.yml index 84bb9e937..5c5cb6562 100644 --- a/.github/workflows/trigger-tag.yml +++ b/.github/workflows/trigger-tag.yml @@ -11,7 +11,7 @@ jobs: steps: # Checkout this repo - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 # Get branch name @@ -24,11 +24,11 @@ jobs: # and 2022.1.1-dev9 will become 2022.1.1-dev10 - name: Get next dev tag name run: | - LAST_TAG=$(git tag --sort=v:refname --merged ${{ env.BRANCH_NAME }} | grep -e '-dev' | tail -1) + LAST_TAG=$(git tag --sort=v:refname --merged ${{ env.BRANCH_NAME }} | grep -E '^[0-9]{4}\.[0-9]+\.[0-9]+-dev[0-9]+$' | tail -1) echo "NEXT_TAG=$(echo $LAST_TAG | awk -F-dev -v OFS=-dev '{$NF += 1 ; print}')" >> $GITHUB_ENV # Trigger the build - name: Trigger the tagger workflow with branch ${{env.BRANCH_NAME}} and tag ${{ env.NEXT_TAG }} - uses: actions/github-script@v5 + uses: actions/github-script@v7 with: github-token: ${{ secrets.ACAS_WORKFLOWS_TOKEN }} script: | diff --git a/Dockerfile-multistage b/Dockerfile-multistage index c5ed6370a..da0392e91 100644 --- a/Dockerfile-multistage +++ b/Dockerfile-multistage @@ -27,7 +27,7 @@ RUN apt-get update && \ # Add nodejs for prepare config files ENV NPM_CONFIG_LOGLEVEL warn -ENV NODE_VERSION 18.x +ENV NODE_VERSION 20.x # Second Slowest Step RUN curl -fsSL https://deb.nodesource.com/setup_$NODE_VERSION | bash - && \ diff --git a/find-sort-flywaymigration.bash b/find-sort-flywaymigration.bash new file mode 100644 index 000000000..cbf8c5197 --- /dev/null +++ b/find-sort-flywaymigration.bash @@ -0,0 +1,38 @@ +# /bin/bash + +# Find all the flyway migration files and sort them in order of version number (semantically) +# write them out as tab separated values with version\tfile + +java_files=$( find src/main/java/com/labsynch/labseer/db/migration -name "V*.java" ) + +# Loop through the files and get the version from the beginning of the file name +# e.g. src/main/java/com/labsynch/labseer/db/migration/postgres/V1_0_6_6__copy_author_value_blob_values.java -> 1_0_6_6 +all_versions="" +for java_file in $java_files +do + file_name=$( basename $java_file ) + version=$( echo $file_name | sed -e 's/V\([0-9_]*\)__.*/\1/' | sed -e 's/_/./g' ) + # add java to the end of the version + version="$version\t$java_file" + all_versions="$all_versions $version" +done + +# Get teh sql files in src/main/resources/db/migration/postgres +sql_files=$( find src/main/resources/db/migration -name "*.sql" ) + +# Loop through the files and get the version from the beginning of the file name +# e.g. src/main/resources/db/migration/postgres/V1_0_6_6__copy_author_value_blob_values.sql -> 1_0_6_6 +for sql_file in $sql_files +do + file_name=$( basename $sql_file ) + version=$( echo $file_name | sed -e 's/V\([0-9.]*\)__.*/\1/' ) + version="$version\t$sql_file" + all_versions="$all_versions $version" +done + + +# Do a semantically sorted list of the versions +# Use printf to get the tabs to work +printf "version\tfile" +printf "$all_versions" | tr ' ' '\n' | sort -V + diff --git a/src/main/java/com/labsynch/labseer/api/ApiDDictValueController.java b/src/main/java/com/labsynch/labseer/api/ApiDDictValueController.java index 3a97c55b3..21cb5c61a 100644 --- a/src/main/java/com/labsynch/labseer/api/ApiDDictValueController.java +++ b/src/main/java/com/labsynch/labseer/api/ApiDDictValueController.java @@ -4,6 +4,8 @@ import java.util.Collection; import java.util.List; +import javax.persistence.TypedQuery; + import com.labsynch.labseer.domain.DDictValue; import com.labsynch.labseer.dto.CodeTableDTO; import com.labsynch.labseer.exceptions.ErrorMessage; @@ -322,7 +324,10 @@ public ResponseEntity listJson( public ResponseEntity getDDictValuesByTypeKindFormat( @PathVariable("lsType") String lsType, @PathVariable("lsKind") String lsKind, - @PathVariable("format") String format) { + @PathVariable("format") String format, + @RequestParam(value = "maxHits", required = false) Integer maxHits, + @RequestParam(value = "shortName", defaultValue = "", required = false) String shortName, + @RequestParam(value = "labelTextSearchTerm", defaultValue = "", required = false) String labelTextSearchTerm) { HttpHeaders headers = new HttpHeaders(); headers.add("Content-Type", "application/json; charset=utf-8"); @@ -331,12 +336,37 @@ public ResponseEntity getDDictValuesByTypeKindFormat( return new ResponseEntity(headers, HttpStatus.BAD_REQUEST); } - List dDictResults = DDictValue.findDDictValuesByLsTypeEqualsAndLsKindEquals(lsType, lsKind) - .getResultList(); + // throw an error if the user tries to search by codeName and label text + if (!shortName.isEmpty() && !labelTextSearchTerm.isEmpty()) { + ErrorMessage errorMessage = new ErrorMessage(); + errorMessage.setErrorLevel("error"); + errorMessage.setMessage("Cannot search by codeName and labelTextSearchTerm at the same time"); + return new ResponseEntity(errorMessage.toJson(), headers, HttpStatus.BAD_REQUEST); + } + + List dDictResults; + if (labelTextSearchTerm.isEmpty() && shortName.isEmpty()) { + TypedQuery dDictResultsQuery = DDictValue.findDDictValuesByLsTypeEqualsAndLsKindEquals(lsType, lsKind); + if (maxHits != null) { + dDictResultsQuery = dDictResultsQuery.setMaxResults(maxHits); + } + dDictResults = dDictResultsQuery.getResultList(); + } else if (!shortName.isEmpty()) { + TypedQuery dDictResultsQuery = DDictValue.findDDictValuesByLsTypeEqualsAndLsKindEqualsAndShortNameEquals(lsType, lsKind, shortName); + if (maxHits != null) { + dDictResultsQuery = dDictResultsQuery.setMaxResults(maxHits); + } + dDictResults = dDictResultsQuery.getResultList(); + } else { + dDictResults = DDictValue.findDDictValuesByLsTypeEqualsAndLsKindEqualsAndLabelTextSearch(lsType, lsKind, labelTextSearchTerm, maxHits); + } if (format != null && format.equalsIgnoreCase("codeTable")) { List codeTables = dataDictionaryService.convertToCodeTables(dDictResults); - codeTables = CodeTableDTO.sortCodeTables(codeTables); + // labelText searches have their own sort order so we don't need to sort them + if (labelTextSearchTerm.isEmpty()) { + codeTables = CodeTableDTO.sortCodeTables(codeTables); + } return new ResponseEntity(CodeTableDTO.toJsonArray(codeTables), headers, HttpStatus.OK); } else if (format != null && format.equalsIgnoreCase("csv")) { String outputString = dataDictionaryService.getCsvList(dDictResults); diff --git a/src/main/java/com/labsynch/labseer/api/ApiExperimentController.java b/src/main/java/com/labsynch/labseer/api/ApiExperimentController.java index d6bfd2857..6107a51ba 100755 --- a/src/main/java/com/labsynch/labseer/api/ApiExperimentController.java +++ b/src/main/java/com/labsynch/labseer/api/ApiExperimentController.java @@ -44,6 +44,7 @@ import com.labsynch.labseer.dto.TsvLoaderResponseDTO; import com.labsynch.labseer.exceptions.ErrorMessage; import com.labsynch.labseer.exceptions.NotFoundException; +import com.labsynch.labseer.exceptions.TooManyResultsException; import com.labsynch.labseer.exceptions.UniqueNameException; import com.labsynch.labseer.service.AnalysisGroupService; import com.labsynch.labseer.service.AnalysisGroupValueService; @@ -1634,20 +1635,19 @@ public ResponseEntity jsonFindExperimentByNameGet(@RequestPara @RequestMapping(value = "/protocol/{codeName}", method = RequestMethod.GET, headers = "Accept=application/json") @ResponseBody public ResponseEntity jsonFindExperimentsByProtocolCodeName( - @PathVariable("codeName") String codeName, @RequestParam(value = "with", required = false) String with) { + @PathVariable("codeName") String codeName, @RequestParam(value = "projects", required = false) List projects, @RequestParam(value = "with", required = false) String with) { HttpHeaders headers = new HttpHeaders(); headers.add("Content-Type", "application/json; charset=utf-8"); - List protocols = Protocol.findProtocolsByCodeNameEqualsAndIgnoredNot(codeName, true).getResultList(); - if (protocols.size() == 1) { + try { + Collection experiments = experimentService.findExperimentsByProtocolCodeName(codeName, projects); return new ResponseEntity( - Experiment.toJsonArrayStub(Experiment.findExperimentsByProtocol(protocols.get(0)).getResultList()), + Experiment.toJsonArrayStub(experiments), headers, HttpStatus.OK); - } else if (protocols.size() > 1) { - logger.error("ERROR: multiple protocols found with the same code name"); - return new ResponseEntity("[ ]", headers, HttpStatus.CONFLICT); - } else { - logger.warn("WARN: no protocols found with the query code name"); + } catch (NoResultException e) { return new ResponseEntity("[ ]", headers, HttpStatus.NOT_FOUND); + + } catch (TooManyResultsException e) { + return new ResponseEntity("[ ]", headers, HttpStatus.CONFLICT); } } diff --git a/src/main/java/com/labsynch/labseer/chemclasses/bbchem/BBChemParentStructure.java b/src/main/java/com/labsynch/labseer/chemclasses/bbchem/BBChemParentStructure.java index fbc911f03..cac5a9e00 100644 --- a/src/main/java/com/labsynch/labseer/chemclasses/bbchem/BBChemParentStructure.java +++ b/src/main/java/com/labsynch/labseer/chemclasses/bbchem/BBChemParentStructure.java @@ -32,7 +32,7 @@ public static List findBBChemParentStructuresBySubstructu EntityManager em = BBChemParentStructure.entityManager(); String fingerprintString = SimpleUtil.bitSetToString(substructure); Query q = em.createNativeQuery( - "SELECT o.* FROM bbchem_parent_structure AS o WHERE (o.substructure \\& CAST(:fingerprintString AS bit(2048))) = CAST(:fingerprintString AS bit(2048)) ", + "SELECT o.* FROM bbchem_parent_structure AS o WHERE (o.substructure \\& CAST(:fingerprintString AS bit(2112))) = CAST(:fingerprintString AS bit(2112)) ", BBChemParentStructure.class); q.setParameter("fingerprintString", fingerprintString); if (maxResults > -1) { diff --git a/src/main/java/com/labsynch/labseer/chemclasses/bbchem/BBChemSaltFormStructure.java b/src/main/java/com/labsynch/labseer/chemclasses/bbchem/BBChemSaltFormStructure.java index 64fb14269..23a403df1 100644 --- a/src/main/java/com/labsynch/labseer/chemclasses/bbchem/BBChemSaltFormStructure.java +++ b/src/main/java/com/labsynch/labseer/chemclasses/bbchem/BBChemSaltFormStructure.java @@ -32,7 +32,7 @@ public static List findBBChemSaltFormStructuresBySubstr EntityManager em = BBChemSaltFormStructure.entityManager(); String fingerprintString = SimpleUtil.bitSetToString(substructure); Query q = em.createNativeQuery( - "SELECT o.* FROM bbchem_salt_form_structure AS o WHERE (o.substructure \\& CAST(:fingerprintString AS bit(2048))) = CAST(:fingerprintString AS bit(2048)) ", + "SELECT o.* FROM bbchem_salt_form_structure AS o WHERE (o.substructure \\& CAST(:fingerprintString AS bit(2112))) = CAST(:fingerprintString AS bit(2112)) ", BBChemSaltFormStructure.class); q.setParameter("fingerprintString", fingerprintString); if (maxResults > -1) { diff --git a/src/main/java/com/labsynch/labseer/domain/DDictValue.java b/src/main/java/com/labsynch/labseer/domain/DDictValue.java index c1da13f19..8696dfd86 100644 --- a/src/main/java/com/labsynch/labseer/domain/DDictValue.java +++ b/src/main/java/com/labsynch/labseer/domain/DDictValue.java @@ -11,6 +11,7 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.PersistenceContext; +import javax.persistence.Query; import javax.persistence.SequenceGenerator; import javax.persistence.TypedQuery; import javax.persistence.Version; @@ -568,6 +569,45 @@ public static TypedQuery findDDictValuesByLsTypeEqualsAndLsKindEqual return q; } + public static List findDDictValuesByLsTypeEqualsAndLsKindEqualsAndLabelTextSearch(String lsType, String lsKind, String labelText, Integer maxHits) { + if (lsType == null || lsType.length() == 0) + throw new IllegalArgumentException("The lsType argument is required"); + if (lsKind == null || lsKind.length() == 0) + throw new IllegalArgumentException("The lsKind argument is required"); + EntityManager em = DDictValue.entityManager(); + + // Format the search text to match any word in the label text + // e.g. "word1 word2" -> "word1:* & word2:*" + String[] parts = labelText.trim().split("\\s+"); + for (int i = 0; i < parts.length; i++) { + parts[i] = parts[i] + ":*"; + } + String formattedLabelText = String.join(" & ", parts); + + // Native query to use full text search + String sql = + "SELECT * " + + "FROM ddict_value " + + "WHERE ls_type = :lsType " + + "AND ls_kind = :lsKind " + + "AND to_tsvector('english', lower(label_text)) @@ to_tsquery('english', :formattedLabelText) " + + "ORDER BY (lower(label_text) = :labelText) DESC, " + + "ts_rank(to_tsvector('english', lower(label_text)), to_tsquery('english', :formattedLabelText)) DESC"; + + Query q = em.createNativeQuery(sql, DDictValue.class); + q.setParameter("lsType", lsType); + q.setParameter("lsKind", lsKind); + q.setParameter("labelText", labelText.toLowerCase()); + q.setParameter("formattedLabelText", formattedLabelText); + if (maxHits != null) { + q = q.setMaxResults(maxHits); + } + + @SuppressWarnings("unchecked") + List results = q.getResultList(); + return results; + } + public static TypedQuery findDDictValuesByLsTypeEqualsAndLsKindEquals(String lsType, String lsKind, String sortFieldName, String sortOrder) { if (lsType == null || lsType.length() == 0) diff --git a/src/main/java/com/labsynch/labseer/domain/Lot.java b/src/main/java/com/labsynch/labseer/domain/Lot.java index 06195642b..6d1964431 100755 --- a/src/main/java/com/labsynch/labseer/domain/Lot.java +++ b/src/main/java/com/labsynch/labseer/domain/Lot.java @@ -148,7 +148,7 @@ public class Lot { @Size(max = 255) @Column(name = "vendorid") - private String vendorId; + private String vendorID; @ManyToOne @JoinColumn(name = "salt_form") @@ -618,10 +618,11 @@ public static TypedQuery findLotsByProjectsList(List p EntityManager em = Lot.entityManager(); String query = "SELECT new com.labsynch.labseer.dto.LotsByProjectDTO( " - + "lt.id as id, lt.corpName as lotCorpName, lt.lotNumber as lotNumber, lt.registrationDate as registrationDate, prnt.corpName as parentCorpName, lt.project as project) " + + "lt.id as id, lt.corpName as lotCorpName, lt.lotNumber as lotNumber, lt.registrationDate as registrationDate, prnt.corpName as parentCorpName, lt.project as project, lt.chemist as chemist, vnd.name as vendorName, vnd.code as vendorCode, lt.supplier as supplier) " + "FROM Lot AS lt " + "JOIN lt.saltForm sltfrm " + "JOIN sltfrm.parent prnt " + + "LEFT JOIN lt.vendor vnd " + "WHERE lt.project in (:projects) "; logger.debug("sql query " + query); @@ -898,12 +899,12 @@ public void setVendor(Vendor vendor) { this.vendor = vendor; } - public String getVendorId() { - return this.vendorId; + public String getVendorID() { + return this.vendorID; } - public void setVendorId(String vendorId) { - this.vendorId = vendorId; + public void setVendorID(String vendorID) { + this.vendorID = vendorID; } public Set getFileLists() { @@ -1074,7 +1075,7 @@ public void setLotAliases(Set lotAliases) { "registeredBy", "modifiedDate", "modifiedBy", "barcode", "color", "notebookPage", "amount", "amountUnits", "solutionAmount", "solutionAmountUnits", "supplier", "supplierID", "purity", "purityOperator", "purityMeasuredBy", "chemist", "percentEE", "comments", "isVirtual", "ignore", "physicalState", "vendor", - "vendorId", "saltForm", "fileLists", "retain", "retainUnits", "retainLocation", "meltingPoint", + "vendorID", "saltForm", "fileLists", "retain", "retainUnits", "retainLocation", "meltingPoint", "boilingPoint", "supplierLot", "project", "parent", "bulkLoadFile", "lambda", "absorbance", "stockSolvent", "stockLocation", "observedMassOne", "observedMassTwo", "tareWeight", "tareWeightUnits", "totalAmountStored", "totalAmountStoredUnits", "lotAliases", "storageLocation"); diff --git a/src/main/java/com/labsynch/labseer/domain/SaltForm.java b/src/main/java/com/labsynch/labseer/domain/SaltForm.java index a12d70467..a8f99a8f4 100755 --- a/src/main/java/com/labsynch/labseer/domain/SaltForm.java +++ b/src/main/java/com/labsynch/labseer/domain/SaltForm.java @@ -29,7 +29,9 @@ import javax.persistence.criteria.JoinType; import javax.persistence.criteria.ParameterExpression; import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Expression; import javax.persistence.criteria.Root; +import javax.persistence.criteria.Order; import javax.validation.constraints.Size; import com.labsynch.labseer.dto.SearchFormDTO; @@ -239,6 +241,7 @@ public static TypedQuery findSaltFormsByMeta(SearchFormDTO searchParam Predicate[] predicates = new Predicate[0]; List predicateList = new ArrayList(); + List orderList = new ArrayList(); if (searchParams.getChemist() != null && !searchParams.getChemist().equals("anyone")) { logger.debug("incoming chemist :" + searchParams.getChemist().toString()); @@ -279,9 +282,37 @@ public static TypedQuery findSaltFormsByMeta(SearchFormDTO searchParam predicateList.add(predicate); } if (searchParams.getFormattedCorpNameList() != null) { - logger.debug("incoming corpNameList :" + searchParams.getFormattedCorpNameList().toString()); - Predicate predicate = saltFormParent.get("corpName").in(searchParams.getFormattedCorpNameList()); + List corpNames = searchParams.getFormattedCorpNameList(); + logger.debug("incoming corpNameList :" + corpNames.toString()); + ArrayList corpNameLikePredicates = new ArrayList(); + Expression maxSimilarity = null; + for (String corpName : corpNames) { + Predicate predicate = criteriaBuilder.like(saltFormParent.get("corpName"), '%' + corpName); + corpNameLikePredicates.add(predicate); + // Using pg_trgm.similarity to order results based on how similar the value is to + // the formatted corporate names. + Expression similarity = criteriaBuilder.function( + "similarity", + Double.class, + saltFormParent.get("corpName"), + criteriaBuilder.literal(corpName) + ); + if (maxSimilarity == null) { + maxSimilarity = similarity; + } + else { + maxSimilarity = criteriaBuilder.selectCase() + .when(criteriaBuilder.greaterThan(similarity, maxSimilarity), similarity) + .otherwise(maxSimilarity) + .as(Double.class); + } + } + Predicate predicate = criteriaBuilder.or(corpNameLikePredicates.toArray(new Predicate[0])); predicateList.add(predicate); + if (maxSimilarity != null) { + // Rows with a higher similarity will be ordered first. + orderList.add(criteriaBuilder.desc(maxSimilarity)); + } } if (searchParams.getAlias() != null && !searchParams.getAlias().equals("")) { Predicate predicate = null; @@ -329,6 +360,7 @@ public static TypedQuery findSaltFormsByMeta(SearchFormDTO searchParam predicates = predicateList.toArray(predicates); criteria.where(criteriaBuilder.and(predicates)); + criteria.orderBy(orderList); TypedQuery q = em.createQuery(criteria); if (searchParams.getMaxSynthDate() != null) { diff --git a/src/main/java/com/labsynch/labseer/dto/FileSaveSendDTO.java b/src/main/java/com/labsynch/labseer/dto/FileSaveSendDTO.java index 8d7cab19c..2ab018070 100755 --- a/src/main/java/com/labsynch/labseer/dto/FileSaveSendDTO.java +++ b/src/main/java/com/labsynch/labseer/dto/FileSaveSendDTO.java @@ -8,6 +8,7 @@ import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import javax.persistence.Transient; @@ -59,6 +60,11 @@ public List saveFile() { List writeupList = this.writeup; + // If writeupList is empty, fill it with empty strings to match the size of fileList + if (writeupList.isEmpty()) { + writeupList = new ArrayList<>(Collections.nCopies(fileList.size(), "")); + } + List fileSaveArray = new ArrayList(); logger.debug("FileSaveSendDTO: Number of files to save: " + fileList.size()); diff --git a/src/main/java/com/labsynch/labseer/dto/LotDTO.java b/src/main/java/com/labsynch/labseer/dto/LotDTO.java index 48d617547..f7653bd7d 100755 --- a/src/main/java/com/labsynch/labseer/dto/LotDTO.java +++ b/src/main/java/com/labsynch/labseer/dto/LotDTO.java @@ -4,6 +4,7 @@ import java.util.Date; import java.util.List; +import com.fasterxml.jackson.annotation.JsonAlias; import com.labsynch.labseer.domain.IsoSalt; import com.labsynch.labseer.domain.Lot; import com.labsynch.labseer.domain.LotAlias; @@ -67,7 +68,7 @@ public class LotDTO { private Double totalAmountStored; private String totalAmountStoredUnitsCode; private String vendorCode; - private String vendorId; + private String vendorID; private String saltFormCorpName; private String casNumber; private String saltAbbrevs; @@ -598,12 +599,12 @@ public void setVendorCode(String vendorCode) { this.vendorCode = vendorCode; } - public String getVendorId() { - return this.vendorId; + public String getVendorID() { + return this.vendorID; } - public void setVendorId(String vendorId) { - this.vendorId = vendorId; + public void setVendorID(String vendorID) { + this.vendorID = vendorID; } public String getSaltFormCorpName() { diff --git a/src/main/java/com/labsynch/labseer/dto/LotsByProjectDTO.java b/src/main/java/com/labsynch/labseer/dto/LotsByProjectDTO.java index 5f0ff79a6..a8bb4c072 100755 --- a/src/main/java/com/labsynch/labseer/dto/LotsByProjectDTO.java +++ b/src/main/java/com/labsynch/labseer/dto/LotsByProjectDTO.java @@ -13,6 +13,10 @@ public class LotsByProjectDTO { private Date registrationDate; private String parentCorpName; private String project; + private String chemist; + private String vendorName; + private String vendorCode; + private String supplier; public LotsByProjectDTO( long id, @@ -20,7 +24,11 @@ public LotsByProjectDTO( int lotNumber, Date registrationDate, String parentCorpName, - String project) { + String project, + String chemist, + String vendorName, + String vendorCode, + String supplier) { this.id = id; this.lotCorpName = lotCorpName; @@ -28,6 +36,10 @@ public LotsByProjectDTO( this.registrationDate = registrationDate; this.parentCorpName = parentCorpName; this.project = project; + this.chemist = chemist; + this.vendorName = vendorName; + this.vendorCode = vendorCode; + this.supplier = supplier; } public LotsByProjectDTO() { @@ -50,6 +62,38 @@ public void setLotCorpName(String lotCorpName) { this.lotCorpName = lotCorpName; } + public String getChemist() { + return this.chemist; + } + + public void setChemist(String chemist) { + this.chemist = chemist; + } + + public String getVendorName() { + return this.vendorName; + } + + public void setVendorName(String vendorName) { + this.vendorName = vendorName; + } + + public String getVendorCode() { + return this.vendorCode; + } + + public void setVendorCode(String vendorCode) { + this.vendorCode = vendorCode; + } + + public String getSupplier() { + return this.supplier; + } + + public void setSupplier(String supplier) { + this.supplier = supplier; + } + public Integer getLotNumber() { return this.lotNumber; } diff --git a/src/main/java/com/labsynch/labseer/dto/SearchFormReturnDTO.java b/src/main/java/com/labsynch/labseer/dto/SearchFormReturnDTO.java index 6bdf8593b..605787b06 100755 --- a/src/main/java/com/labsynch/labseer/dto/SearchFormReturnDTO.java +++ b/src/main/java/com/labsynch/labseer/dto/SearchFormReturnDTO.java @@ -15,7 +15,7 @@ public class SearchFormReturnDTO { - private Collection foundCompounds = new HashSet(); + private Collection foundCompounds = new ArrayList(); private boolean lotsWithheld; diff --git a/src/main/java/com/labsynch/labseer/service/BulkLoadServiceImpl.java b/src/main/java/com/labsynch/labseer/service/BulkLoadServiceImpl.java index 1b1e2702e..514014126 100644 --- a/src/main/java/com/labsynch/labseer/service/BulkLoadServiceImpl.java +++ b/src/main/java/com/labsynch/labseer/service/BulkLoadServiceImpl.java @@ -609,24 +609,7 @@ public Boolean registerMol(CmpdRegMolecule mol, CmpdRegMolecule standardizedMol, if (validate) { try { - parent = validateParentAgainstDryRunCompound(parent, numRecordsRead, results); - // Check list of aliases within file being bulkloaded - if (!propertiesUtilService.getAllowDuplicateParentAliases()) { - for (ParentAlias alias : parent.getParentAliases()) { - // Skip ignored and deleted aliases - if (alias.isDeleted() | alias.isIgnored()) { - continue; - } - // Make sure the parent doesn't already have this alias name - if (allAliasMaps.get(alias.getAliasName()) == null) { - allAliasMaps.put(alias.getAliasName(), numRecordsRead); - } else { - throw new NonUniqueAliasException( - "Within File, Parent Alias " + alias.getAliasName() - + " is not unique"); - } - } - } + parent = validateParentAgainstDryRunCompound(parent, numRecordsRead, allAliasMaps, results); saveDryRunCompound(mol, parent, numRecordsRead, dryRunCompound); } catch (TransactionSystemException rollbackException) { @@ -725,8 +708,8 @@ public void writeRegisteredMol(int numRecordsRead, CmpdRegMolecule mol, MetalotR ((metalotReturn.getMetalot().getLot().getSupplierID() == null) ? "" : metalotReturn.getMetalot().getLot().getSupplierID())); mol.setProperty("Registered Lot Vendor ID", - ((metalotReturn.getMetalot().getLot().getVendorId() == null) ? "" - : metalotReturn.getMetalot().getLot().getVendorId())); + ((metalotReturn.getMetalot().getLot().getVendorID() == null) ? "" + : metalotReturn.getMetalot().getLot().getVendorID())); if (!parentAliasList.isEmpty()) { for (String alias : parentAliasList) { if (allParentAliases.length() == 0) @@ -1050,15 +1033,16 @@ public Parent validateParent(Parent parent, String chemist, Collection validationResponse) + HashMap allAliasMaps, Collection validationResponse) throws MissingPropertyException, DupeParentException, SaltedCompoundException, Exception { int[] dupeDryRunCompoundsList = chemStructureService.searchMolStructures(parent.getCmpdRegMolecule(), StructureType.DRY_RUN, ChemStructureService.SearchType.DUPLICATE_TAUTOMER, -1F, -1); + DupeParentException dupeException = null; + int existingParentCdId = -1; if (dupeDryRunCompoundsList.length > 0) { searchResultLoop: for (int foundParentCdId : dupeDryRunCompoundsList) { List foundDryRunCompounds = DryRunCompound.findDryRunCompoundsByCdId(foundParentCdId) .getResultList(); - DupeParentException dupeException = null; String categoryDescription; for (DryRunCompound foundDryRunCompound : foundDryRunCompounds) { // same structure @@ -1093,6 +1077,7 @@ public Parent validateParentAgainstDryRunCompound(Parent parent, int numRecordsR if (sameStereoCategory & sameStereoComment & (sameCorpName | (noCorpName & (noCorpNameDryRunCompound | sameCorpPrefixOrNoPrefix)))) { // parents match + existingParentCdId = foundParentCdId; break searchResultLoop; } else if (sameStereoCategory & sameStereoComment & !sameCorpName & !noCorpName) { // corp name conflict @@ -1169,7 +1154,7 @@ public Parent validateParentAgainstDryRunCompound(Parent parent, int numRecordsR } } if (dupeException != null) { - throw dupeException; + break; } } } else { @@ -1183,13 +1168,38 @@ public Parent validateParentAgainstDryRunCompound(Parent parent, int numRecordsR if (dryRunCmpds.size() > 0) { logger.error("Within file, parent corp name already exists for a different parent structure: " + dryRunCmpds.get(0).getCorpName()); - throw new DupeParentException("Within file, parent corp name " + dryRunCmpds.get(0).getCorpName() + dupeException = new DupeParentException("Within file, parent corp name " + dryRunCmpds.get(0).getCorpName() + " already exists for a different parent structure record number " + dryRunCmpds.get(0).getRecordNumber()); } } } - + if (dupeException != null) { + throw dupeException; + } else { + if (!propertiesUtilService.getAllowDuplicateParentAliases() && parent.getId() == null && existingParentCdId == -1) { + // We now know: + // we are enforcing unique aliases + // this isn't a dupe structure (didn't already throw dupe exception) + // this isn't an existing parent (existing parent id is null) + // this isn't a second batch of a parent that already exists in the file (existing parent cd id is -1) + // This means that the parent is new and we need to check for duplicate aliases using our map of all aliases + for (ParentAlias alias : parent.getParentAliases()) { + // Skip ignored and deleted aliases + if (alias.isDeleted() | alias.isIgnored()) { + continue; + } + // Make sure the parent doesn't already have this alias name + if (allAliasMaps.get(alias.getAliasName()) == null) { + allAliasMaps.put(alias.getAliasName(), numRecordsRead); + } else { + throw new NonUniqueAliasException( + "Within File, Parent Alias " + alias.getAliasName() + + " is not unique"); + } + } + } + } return parent; } @@ -1384,7 +1394,7 @@ public Lot createLot(CmpdRegMolecule mol, int recordNumber, Collection getExperimentNodesByProtocolTree( public Collection findExperimentsByMetadataJson( List metaDataList); + + public Collection findExperimentsByProtocolCodeName(String query, List projects) + throws TooManyResultsException; + public Collection findExperimentsByGenericMetaDataSearch(String query, String userName, Boolean includeDeleted) throws TooManyResultsException; diff --git a/src/main/java/com/labsynch/labseer/service/ExperimentServiceImpl.java b/src/main/java/com/labsynch/labseer/service/ExperimentServiceImpl.java index 87c4b5101..cc0ef0159 100755 --- a/src/main/java/com/labsynch/labseer/service/ExperimentServiceImpl.java +++ b/src/main/java/com/labsynch/labseer/service/ExperimentServiceImpl.java @@ -1118,6 +1118,45 @@ public Collection findExperimentsByGenericMetaDataSearch(String quer } + public Collection findExperimentsByProtocolCodeName(String codeName, List projects) + throws TooManyResultsException, NoResultException { + List protocols = Protocol.findProtocolsByCodeNameEqualsAndIgnoredNot(codeName, true).getResultList(); + + if (protocols.size() > 1) { + logger.error("ERROR: multiple protocols found with the same code name"); + throw new TooManyResultsException("ERROR: multiple protocols found with the same code name"); + } else if (protocols.size() < 1) { + logger.warn("WARN: no protocols found with the query code name"); + throw new NoResultException("WARN: no protocols found with the query code name"); + } + + Collection rawResults = Experiment.findExperimentsByProtocol(protocols.get(0)).getResultList(); + if (propertiesUtilService.getRestrictExperiments()) { + projects.add("unassigned"); + Collection results = new HashSet(); + for (Experiment rawResult : rawResults) { + String experimentProject = null; + for (ExperimentState state : rawResult.getLsStates()) { + if (!state.isIgnored() && !state.isDeleted()) { + for (ExperimentValue value : state.getLsValues()) { + if (value.getLsKind().equals("project") && !value.getDeleted() && !value.getIgnored()) { + experimentProject = value.getCodeValue(); + break; + } + } + } + } + if (projects.contains(experimentProject)) { + results.add(rawResult); + } + } + return results; + } else { + return rawResults; + } + + } + @Override public Collection findExperimentsByGenericMetaDataSearch(String queryString, List projects, Boolean includeDeleted) throws TooManyResultsException { diff --git a/src/main/java/com/labsynch/labseer/service/ExportServiceImpl.java b/src/main/java/com/labsynch/labseer/service/ExportServiceImpl.java index 54bbafa14..d61be6757 100644 --- a/src/main/java/com/labsynch/labseer/service/ExportServiceImpl.java +++ b/src/main/java/com/labsynch/labseer/service/ExportServiceImpl.java @@ -181,8 +181,8 @@ private int writeLotsToSDF(String exportSDFFileName, Collection lotDTOs) mol.setProperty("Supplier", lotDTO.getSupplier()); if (lotDTO.getSupplierID() != null) mol.setProperty("Supplier ID", lotDTO.getSupplierID()); - if (lotDTO.getVendorId() != null) - mol.setProperty("Vendor ID", lotDTO.getVendorId()); + if (lotDTO.getVendorID() != null) + mol.setProperty("Vendor ID", lotDTO.getVendorID()); if (lotDTO.getSupplierLot() != null) mol.setProperty("Supplier Lot", lotDTO.getSupplierLot()); if (lotDTO.getSynthesisDate() != null) diff --git a/src/main/java/com/labsynch/labseer/service/LabelSequenceServiceImpl.java b/src/main/java/com/labsynch/labseer/service/LabelSequenceServiceImpl.java index d977fdcae..5cf87e519 100644 --- a/src/main/java/com/labsynch/labseer/service/LabelSequenceServiceImpl.java +++ b/src/main/java/com/labsynch/labseer/service/LabelSequenceServiceImpl.java @@ -30,11 +30,16 @@ public Collection saveLabelSequenceArray( for (LabelSequence labelSequence : labelSequences) { LabelSequence savedLabelSequence; try { + logger.info("Looking for existing LabelSequence: '" + labelSequence.getThingTypeAndKind() + "' '" + + labelSequence.getLabelTypeAndKind() + "'"); savedLabelSequence = LabelSequence .findLabelSequencesByThingTypeAndKindEqualsAndLabelTypeAndKindEquals( labelSequence.getThingTypeAndKind(), labelSequence.getLabelTypeAndKind()) .getSingleResult(); + logger.info("Found existing LabelSequence: '" + savedLabelSequence.getThingTypeAndKind() + "' '" + + savedLabelSequence.getLabelTypeAndKind() + "'"); } catch (NoResultException e) { + logger.info("No existing LabelSequence found, creating new one"); savedLabelSequence = labelSequence; savedLabelSequence.save(); } diff --git a/src/main/java/com/labsynch/labseer/service/MetalotServiceImpl.java b/src/main/java/com/labsynch/labseer/service/MetalotServiceImpl.java index e04e33a58..7885ab6b6 100755 --- a/src/main/java/com/labsynch/labseer/service/MetalotServiceImpl.java +++ b/src/main/java/com/labsynch/labseer/service/MetalotServiceImpl.java @@ -618,7 +618,7 @@ public MetalotReturn processAndSave(Metalot metaLot, MetalotReturn mr, ArrayList // oldLot.setObservedMassOne(lot.getObservedMassOne()); oldLot.setObservedMassTwo(lot.getObservedMassTwo()); - oldLot.setVendorId(lot.getVendorId()); + oldLot.setVendorID(lot.getVendorID()); oldLot.setTareWeight(lot.getTareWeight()); oldLot.setTareWeightUnits(lot.getTareWeightUnits()); oldLot.setTotalAmountStored(lot.getTotalAmountStored()); diff --git a/src/main/java/com/labsynch/labseer/service/SearchFormServiceImpl.java b/src/main/java/com/labsynch/labseer/service/SearchFormServiceImpl.java index 3ba7aa3f6..4704b9d33 100755 --- a/src/main/java/com/labsynch/labseer/service/SearchFormServiceImpl.java +++ b/src/main/java/com/labsynch/labseer/service/SearchFormServiceImpl.java @@ -186,15 +186,16 @@ public SearchFormReturnDTO findQuerySaltForms(SearchFormDTO searchParams) throws if (!searchParams.getCorpNameList().equals("")) { logger.info("got a corp name list search!"); String[] inputListArray = searchParams.getCorpNameList().split("[\\s,;\\n\\r]+"); - List formattedCorpNameList = new ArrayList(); + HashSet uniqueCorpNames = new HashSet<>(); for (String corpName : inputListArray) { - logger.info(corpNameService.formatCorpName(corpNameService.parseParentNumber(corpName))); - formattedCorpNameList.add(corpName); - formattedCorpNameList.add(corpNameService.formatCorpName(corpNameService.parseParentNumber(corpName))); - + uniqueCorpNames.add(corpName); + // Remove the prefix, lot. + String parentNumber = corpNameService.parseParentNumber(corpName).toString(); + uniqueCorpNames.add(parentNumber); } - searchParams.setFormattedCorpNameList(formattedCorpNameList); - logger.info(formattedCorpNameList.toString()); + List corpNames = new ArrayList(uniqueCorpNames); + logger.info(corpNames.toString()); + searchParams.setFormattedCorpNameList(corpNames); } // Check if corpNameFrom and corpNameTo are both set -- will search for a range // of parents if both set @@ -612,7 +613,7 @@ public SearchFormReturnDTO findQuerySaltForms(SearchFormDTO searchParams) throws private SearchFormReturnDTO filterSearchResultsByProject(SearchFormReturnDTO searchResults, List projects) { if (!searchResults.getFoundCompounds().isEmpty()) { - Collection filteredFoundCompounds = new HashSet(); + Collection filteredFoundCompounds = new ArrayList(); for (SearchCompoundReturnDTO foundCompound : searchResults.getFoundCompounds()) { List filteredFoundLots = new ArrayList(); for (SearchLotDTO foundLot : foundCompound.getLotIDs()) { diff --git a/src/main/java/com/labsynch/labseer/utils/GlobalErrorHandler.java b/src/main/java/com/labsynch/labseer/utils/GlobalErrorHandler.java new file mode 100644 index 000000000..1ed254e32 --- /dev/null +++ b/src/main/java/com/labsynch/labseer/utils/GlobalErrorHandler.java @@ -0,0 +1,68 @@ +package com.labsynch.labseer.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +import java.io.PrintWriter; +import java.io.StringWriter; + +@ControllerAdvice +public class GlobalErrorHandler { + + private static final Logger logger = LoggerFactory.getLogger(GlobalErrorHandler.class); + + @ExceptionHandler(Exception.class) + public ResponseEntity handleException(Exception ex) { + // Log the exception + logger.error("An error occurred: ", ex); + + // Create an ErrorResponse object with the error message and stack trace + ErrorResponse errorResponse; + if (ex instanceof NullPointerException) { + errorResponse = new ErrorResponse("NullPointerException occurred", getStackTraceAsString(ex)); + } else { + errorResponse = new ErrorResponse(ex.getMessage(), getStackTraceAsString(ex)); + } + + // Return the ErrorResponse as a JSON response with an appropriate HTTP status + return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); + } + + private String getStackTraceAsString(Exception ex) { + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + ex.printStackTrace(printWriter); + return stringWriter.toString(); + } + + // Define the ErrorResponse class + private static class ErrorResponse { + private String errorMessage; + private String stackTrace; + + public ErrorResponse(String errorMessage, String stackTrace) { + this.errorMessage = errorMessage; + this.stackTrace = stackTrace; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public String getStackTrace() { + return stackTrace; + } + + public void setStackTrace(String stackTrace) { + this.stackTrace = stackTrace; + } + } +} diff --git a/src/main/java/com/labsynch/labseer/utils/MimeTypeUtil.java b/src/main/java/com/labsynch/labseer/utils/MimeTypeUtil.java index 64eb43034..8b5504f8a 100755 --- a/src/main/java/com/labsynch/labseer/utils/MimeTypeUtil.java +++ b/src/main/java/com/labsynch/labseer/utils/MimeTypeUtil.java @@ -26,7 +26,7 @@ public static String getContentTypeFromExtension(String originalFilename) { mimeTypeStream = ApiFileSaveController.class.getClassLoader().getResourceAsStream(MIME_PROP_FILE); Properties mimeTypeProps = new Properties(); mimeTypeProps.load(mimeTypeStream); - contentType = mimeTypeProps.getProperty(fileExtension); + contentType = mimeTypeProps.getProperty(fileExtension.toLowerCase()); logger.debug("here is the file contentType: " + contentType); } catch (IOException e) { diff --git a/src/main/resources/db/migration/bbchem/postgres/V2.4.2.2__bbchem_small_vs_bio_molecule_fingerprint_bit.sql b/src/main/resources/db/migration/bbchem/postgres/V2.4.2.2__bbchem_small_vs_bio_molecule_fingerprint_bit.sql new file mode 100644 index 000000000..07bddcdf0 --- /dev/null +++ b/src/main/resources/db/migration/bbchem/postgres/V2.4.2.2__bbchem_small_vs_bio_molecule_fingerprint_bit.sql @@ -0,0 +1,20 @@ +-- Alter each of the bbchem structure.substructure columns to be of type bit(2112) from bit(2048) by adding 1 to the length. +-- This is because the new substructure column is 64 bits longer than the old one with an additional 1 for the small vs bio molecule fingerprint. +DO $$ +DECLARE + table_names text[] := array[ + 'bbchem_standardization_dry_run_structure', + 'bbchem_dry_run_structure', + 'bbchem_parent_structure', + 'bbchem_salt_form_structure', + 'bbchem_salt_structure' + ]; + table_name text; +BEGIN + FOREACH table_name IN ARRAY table_names + LOOP + -- Truncate the table to avoid any issues with the new column length acas will fill it back on startup. + EXECUTE 'TRUNCATE TABLE ' || table_name; + EXECUTE 'ALTER TABLE ' || table_name || ' ALTER COLUMN substructure TYPE bit(2112)'; + END LOOP; +END $$; diff --git a/src/main/resources/db/migration/bbchem/postgres/V2.4.2.3__bbchem_structure_comment_field_expansion.sql b/src/main/resources/db/migration/bbchem/postgres/V2.4.2.3__bbchem_structure_comment_field_expansion.sql new file mode 100644 index 000000000..eab7a9209 --- /dev/null +++ b/src/main/resources/db/migration/bbchem/postgres/V2.4.2.3__bbchem_structure_comment_field_expansion.sql @@ -0,0 +1,45 @@ +-- Set the comment fields of the bbchem structure tables to be of type text +DO $$ +DECLARE + table_names text[] := array[ + 'bbchem_standardization_dry_run_structure', + 'bbchem_dry_run_structure', + 'bbchem_parent_structure', + 'bbchem_salt_form_structure', + 'bbchem_salt_structure' + ]; + column_names text[] := array[ 'registration_comment', 'standardization_comment' ]; + tbl_name text; + col_name text; +BEGIN + FOREACH tbl_name IN ARRAY table_names + LOOP + FOREACH col_name IN ARRAY column_names + LOOP + -- If this is fresh instance then the columns won't exist at all so we create them + IF NOT EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_name = tbl_name + AND column_name = col_name + ) THEN + RAISE NOTICE 'Column % does not exist in table % so creating it', col_name, tbl_name; + EXECUTE 'ALTER TABLE ' || tbl_name || ' ADD COLUMN ' || col_name || ' text'; + CONTINUE; + END IF; + -- If we got here, then the columns exist but may be the wrong type varchar(255) created by hibernate + -- Check if the registration_comment and standardization_comment columns are already text columns. + -- If they are not, then alter them to be text columns. + IF NOT EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_name = tbl_name + AND column_name = col_name + AND data_type = 'text' + ) THEN + RAISE NOTICE 'Altering column % in table % to be of type text', col_name, tbl_name; + EXECUTE 'ALTER TABLE ' || tbl_name || ' ALTER COLUMN ' || col_name || ' TYPE text'; + END IF; + END LOOP; + END LOOP; +END $$; diff --git a/src/main/resources/db/migration/postgres/V2.4.2.1__add_label_sequence_ddict_value_partial_unique_indexes.sql b/src/main/resources/db/migration/postgres/V2.4.2.1__add_label_sequence_ddict_value_partial_unique_indexes.sql new file mode 100644 index 000000000..45474ec6b --- /dev/null +++ b/src/main/resources/db/migration/postgres/V2.4.2.1__add_label_sequence_ddict_value_partial_unique_indexes.sql @@ -0,0 +1,6 @@ +CREATE UNIQUE INDEX IF NOT EXISTS label_sequence_thing_label_prefix_key + ON label_sequence (thing_type_and_kind, label_type_and_kind, label_prefix) + WHERE ignored IS FALSE; +CREATE UNIQUE INDEX IF NOT EXISTS ddict_value_code_type_kind_short_name_key + ON ddict_value (ls_type, ls_kind, short_name) + WHERE ignored IS FALSE; diff --git a/src/main/resources/db/migration/postgres/V2.4.2.4__ddict_value_label_text_search_index.sql b/src/main/resources/db/migration/postgres/V2.4.2.4__ddict_value_label_text_search_index.sql new file mode 100644 index 000000000..25af91929 --- /dev/null +++ b/src/main/resources/db/migration/postgres/V2.4.2.4__ddict_value_label_text_search_index.sql @@ -0,0 +1,27 @@ +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 + FROM pg_class c + JOIN pg_namespace n ON n.oid = c.relnamespace + WHERE c.relname = 'ddict_value_labeltext_tsvector_idx' + ) + THEN + CREATE INDEX ddict_value_labeltext_tsvector_idx ON ddict_value USING GIN (to_tsvector('english', label_text)); + END IF; +END +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 + FROM pg_class c + JOIN pg_namespace n ON n.oid = c.relnamespace + WHERE c.relname = 'idx_ddictvalue_labeltext_lower_pattern' + ) + THEN + CREATE INDEX idx_ddictvalue_labeltext_lower_pattern ON ddict_value(lower(label_text) varchar_pattern_ops); + END IF; +END +$$; \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/spring/webmvc-config.xml b/src/main/webapp/WEB-INF/spring/webmvc-config.xml index d51b9655a..6fe18778b 100755 --- a/src/main/webapp/WEB-INF/spring/webmvc-config.xml +++ b/src/main/webapp/WEB-INF/spring/webmvc-config.xml @@ -25,57 +25,13 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - dataAccessFailure - resourceNotFound - resourceNotFound - resourceNotFound - - - - 500 - - + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 91d00c072..ecb305d15 100755 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -1,6 +1,9 @@ - - + acas @@ -13,6 +16,7 @@ true + contextConfigLocation classpath*:META-INF/spring/applicationContext*.xml @@ -47,6 +51,7 @@ org.springframework.web.filter.HiddenHttpMethodFilter + @@ -139,7 +144,8 @@ org.springframework.web.context.ContextLoaderListener - + + acas org.springframework.web.servlet.DispatcherServlet @@ -149,28 +155,9 @@ 1 - acas / - - - default - /doc/* - - - - 10 - - - - java.lang.Exception - /uncaughtException - - - 404 - /resourceNotFound -