Compare commits

...

5 Commits

Author SHA1 Message Date
Tim Donohue
61f2695b83 Merge pull request #11396 from TexasDigitalLibrary/port_11329_to_7x
[Port dspace-7_x] Fix Hibernate syntax bugs in the CollectionDAO and BitstreamDAO
2025-10-01 16:44:36 -05:00
Tim Donohue
8643888d68 Merge pull request #11399 from tdonohue/port_11139_to_7x
[Port dspace-7_x] fix(#10721): Sanitize non-characters during OAI indexing
2025-10-01 16:39:31 -05:00
JohnnyMendesC
d8fbe16ede fix(#10721): Sanitize non-characters during OAI indexing (#11139)
* fix(#10721): Sanitize non-characters during OAI indexing

* refactor: Use StringEscapeUtils as suggested in review

* fix: Removed whitespace before the import that was causing error

Maven Unit Test failed due to the whitespace before the import
https://github.com/DSpace/DSpace/actions/runs/16891881837/job/47853392956?pr=11139#step:4:1959

* fix: Removed trailing whitespace that was causing error
2025-10-01 15:28:11 -05:00
nwoodward
29e13b77fc checkstyle fix 2025-10-01 13:46:40 -05:00
nwoodward
fc74a7ffdf fix Hibernate bugs 2025-10-01 13:41:41 -05:00
4 changed files with 47 additions and 5 deletions

View File

@@ -152,7 +152,7 @@ public class BitstreamDAOImpl extends AbstractHibernateDSODAO<Bitstream> impleme
@Override
public int countWithNoPolicy(Context context) throws SQLException {
Query query = createQuery(context,
"SELECT count(bit.id) from Bitstream bit where bit.deleted<>true and bit.id not in" +
"SELECT count(bit.id) from Bitstream bit where bit.deleted<>true and bit not in" +
" (select res.dSpaceObject from ResourcePolicy res where res.resourceTypeId = " +
":typeId )");
query.setParameter("typeId", Constants.BITSTREAM);

View File

@@ -12,6 +12,7 @@ import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
@@ -19,6 +20,7 @@ import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.ResourcePolicy_;
import org.dspace.content.Collection;
@@ -40,6 +42,11 @@ import org.dspace.eperson.Group;
* @author kevinvandevelde at atmire.com
*/
public class CollectionDAOImpl extends AbstractHibernateDSODAO<Collection> implements CollectionDAO {
/**
* log4j logger
*/
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(CollectionDAOImpl.class);
protected CollectionDAOImpl() {
super();
}
@@ -172,14 +179,25 @@ public class CollectionDAOImpl extends AbstractHibernateDSODAO<Collection> imple
@SuppressWarnings("unchecked")
public List<Map.Entry<Collection, Long>> getCollectionsWithBitstreamSizesTotal(Context context)
throws SQLException {
String q = "select col as collection, sum(bit.sizeBytes) as totalBytes from Item i join i.collections col " +
"join i.bundles bun join bun.bitstreams bit group by col";
String q = "select col.id, sum(bit.sizeBytes) as totalBytes from Item i join i.collections col " +
"join i.bundles bun join bun.bitstreams bit group by col.id";
Query query = createQuery(context, q);
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
List<Object[]> list = query.getResultList();
List<Map.Entry<Collection, Long>> returnList = new ArrayList<>(list.size());
for (Object[] o : list) {
returnList.add(new AbstractMap.SimpleEntry<>((Collection) o[0], (Long) o[1]));
CriteriaQuery<Collection> criteriaQuery = criteriaBuilder.createQuery(Collection.class);
Root<Collection> collectionRoot = criteriaQuery.from(Collection.class);
criteriaQuery.select(collectionRoot).where(criteriaBuilder.equal(collectionRoot.get("id"), (UUID) o[0]));
Query collectionQuery = createQuery(context, criteriaQuery);
Collection collection = (Collection) collectionQuery.getSingleResult();
if (collection != null) {
returnList.add(new AbstractMap.SimpleEntry<>(collection, (Long) o[1]));
} else {
log.warn("Unable to find Collection with UUID: {}", o[0]);
}
}
return returnList;
}

View File

@@ -464,4 +464,14 @@ public abstract class AbstractHibernateDAO<T> implements GenericDAO<T> {
return executeCriteriaQuery(context, criteria, cacheable, maxResults, offset);
}
/**
* Create a Query object from a CriteriaQuery
* @param context current Context
* @param criteriaQuery CriteriaQuery built via CriteriaBuilder
* @return corresponding Query
* @throws SQLException if error occurs
*/
public Query createQuery(Context context, CriteriaQuery criteriaQuery) throws SQLException {
return this.getHibernateSession(context).createQuery(criteriaQuery);
}
}

View File

@@ -16,6 +16,7 @@ import java.util.List;
import com.lyncode.xoai.dataprovider.xml.xoai.Element;
import com.lyncode.xoai.dataprovider.xml.xoai.Metadata;
import com.lyncode.xoai.util.Base64Utils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.util.factory.UtilServiceFactory;
@@ -159,6 +160,19 @@ public class ItemUtils {
return bundles;
}
/**
* Sanitizes a string to remove characters that are invalid
* in XML 1.0 using the Apache Commons Text library.
* @param value The string to sanitize.
* @return A sanitized string, or null if the input was null.
*/
private static String sanitize(String value) {
if (value == null) {
return null;
}
return StringEscapeUtils.escapeXml10(value);
}
private static Element createLicenseElement(Context context, Item item)
throws SQLException, AuthorizeException, IOException {
Element license = create("license");
@@ -232,7 +246,7 @@ public class ItemUtils {
valueElem = language;
}
valueElem.getField().add(createValue("value", val.getValue()));
valueElem.getField().add(createValue("value", sanitize(val.getValue())));
if (val.getAuthority() != null) {
valueElem.getField().add(createValue("authority", val.getAuthority()));
if (val.getConfidence() != Choices.CF_NOVALUE) {