@SuppressWarnings("unchecked") private AnnotationView buildAnnotationView(Annotation annotation, boolean loadAllReplies) { Object values[]; try { values = (Object[]) hibernateTemplate .findByCriteria( DetachedCriteria.forClass(Article.class) .add(Restrictions.eq("ID", annotation.getArticleID())) .setProjection( Projections.projectionList() .add(Projections.property("doi")) .add(Projections.property("title"))), 0, 1) .get(0); } catch (IndexOutOfBoundsException e) { // this should never happen throw new IllegalStateException( "Annotation " + annotation.getID() + " pointed to an article that didn't exist;" + " articleID: " + annotation.getArticleID()); } String articleDoi = (String) values[0]; String articleTitle = (String) values[1]; return buildAnnotationView(annotation, articleDoi, articleTitle, loadAllReplies); }
@SuppressWarnings("unchecked") private AnnotationView buildAnnotationView( Annotation annotation, String articleDoi, String articleTitle, boolean loadAllReplies) { Map<Long, List<Annotation>> fulReplyMap = null; if (loadAllReplies) { fulReplyMap = buildReplyMap(annotation.getArticleID()); } return new AnnotationView(annotation, articleDoi, articleTitle, fulReplyMap); }
@Override @Transactional public Long createReply( UserProfile user, Long parentId, String title, String body, @Nullable String ciStatement) { if (parentId == null) { throw new IllegalArgumentException("Attempting to create reply with null parent id"); } log.debug("Creating reply to {}; title: {}; body: {}", new Object[] {parentId, title, body}); Long articleID; try { articleID = (Long) hibernateTemplate .findByCriteria( DetachedCriteria.forClass(Annotation.class) .add(Restrictions.eq("ID", parentId)) .setProjection(Projections.property("articleID")), 0, 1) .get(0); } catch (IndexOutOfBoundsException e) { throw new IllegalArgumentException("Invalid annotation id: " + parentId); } Annotation reply = new Annotation(user, AnnotationType.REPLY, articleID); reply.setParentID(parentId); reply.setTitle(title); reply.setBody(body); reply.setCompetingInterestBody(ciStatement); reply.setAnnotationUri(URIGenerator.generate(reply)); return (Long) hibernateTemplate.save(reply); }
@Override @Transactional public Long createComment( UserProfile user, String articleDoi, String title, String body, String ciStatement) { if (articleDoi == null) { throw new IllegalArgumentException("Attempted to create comment with null article id"); } else if (user == null || user.getID() == null) { throw new IllegalArgumentException("Attempted to create comment without a creator"); } else if (body == null || body.isEmpty()) { throw new IllegalArgumentException("Attempted to create comment with no body"); } log.debug( "Creating comment on article: {}; title: {}; body: {}", new Object[] {articleDoi, title, body}); Long articleID; try { articleID = (Long) hibernateTemplate .findByCriteria( DetachedCriteria.forClass(Article.class) .add(Restrictions.eq("doi", articleDoi)) .setProjection(Projections.id())) .get(0); } catch (IndexOutOfBoundsException e) { throw new IllegalArgumentException("Invalid doi: " + articleDoi); } // generate an annotation uri Annotation comment = new Annotation(user, AnnotationType.COMMENT, articleID); comment.setAnnotationUri(URIGenerator.generate(comment)); comment.setTitle(title); comment.setBody(body); comment.setCompetingInterestBody(ciStatement); Long id = (Long) hibernateTemplate.save(comment); return id; }
/** * Build up a map of id, and replies to that id so we can initialize the reply tree * * @param articleId * @return */ @SuppressWarnings("unchecked") private Map<Long, List<Annotation>> buildReplyMap(Long articleId) { Map<Long, List<Annotation>> fullReplyMap = new HashMap<Long, List<Annotation>>(); List<Annotation> allReplies = hibernateTemplate.findByCriteria( DetachedCriteria.forClass(Annotation.class) .add(Restrictions.eq("articleID", articleId)) .add(Restrictions.eq("type", AnnotationType.REPLY))); for (Annotation reply : allReplies) { // parent id should never be null on a reply if (reply.getParentID() == null) { log.warn("Found a reply with null parent id. Reply id: " + reply.getID()); } else { if (!fullReplyMap.containsKey(reply.getParentID())) { fullReplyMap.put(reply.getParentID(), new ArrayList<Annotation>()); } fullReplyMap.get(reply.getParentID()).add(reply); } } return Collections.unmodifiableMap(fullReplyMap); }
protected void checkAnnotationProperties(AnnotationView result, Annotation expected) { if (expected.getType() == AnnotationType.MINOR_CORRECTION) { assertEquals( result.getTitle(), "Minor Correction: " + expected.getTitle(), "Annotation view had incorrect title"); } else if (expected.getType() == AnnotationType.FORMAL_CORRECTION) { assertEquals( result.getTitle(), "Formal Correction: " + expected.getTitle(), "Annotation view had incorrect title"); } else if (expected.getType() == AnnotationType.RETRACTION) { assertEquals( result.getTitle(), "Retraction: " + expected.getTitle(), "Annotation view had incorrect title"); } assertEquals( result.getBody(), "<p>" + expected.getBody() + "</p>", "Annotation view had incorrect body"); assertEquals( result.getCompetingInterestStatement(), expected.getCompetingInterestBody() == null ? "" : expected.getCompetingInterestBody(), "Annotation view had incorrect ci statement"); assertEquals( result.getAnnotationUri(), expected.getAnnotationUri(), "Annotation view had incorrect annotation uri"); assertEquals( result.getCreatorID(), expected.getCreator().getID(), "Annotation view had incorrect creator id"); assertEquals( result.getCreatorDisplayName(), expected.getCreator().getDisplayName(), "Annotation view had incorrect creator name"); if (Arrays.asList( AnnotationType.FORMAL_CORRECTION, AnnotationType.MINOR_CORRECTION, AnnotationType.RETRACTION) .contains(expected.getType())) { assertTrue(result.isCorrection(), "Result should have been created as a correction"); } else { assertFalse(result.isCorrection(), "Result should not have been created as a correction"); } if (expected.getAnnotationCitation() == null) { assertNull(result.getCitation(), "returned non-null citation when null was expected"); } else { assertNotNull(result.getCitation(), "returned null citation when non-null was expected"); assertEquals( result.getCitation().getTitle(), expected.getAnnotationCitation().getTitle(), "Returned citation with incorrect title"); assertEquals( result.getCitation().geteLocationId(), expected.getAnnotationCitation().getELocationId(), "Returned citation with incorrect eLocationId"); assertEquals( result.getCitation().getJournal(), expected.getAnnotationCitation().getJournal(), "Returned citation with incorrect journal"); assertEquals( result.getCitation().getYear(), expected.getAnnotationCitation().getYear(), "Returned citation with incorrect year"); assertEquals( result.getCitation().getVolume(), expected.getAnnotationCitation().getVolume(), "Returned citation with incorrect volume"); assertEquals( result.getCitation().getIssue(), expected.getAnnotationCitation().getIssue(), "Returned citation with incorrect issue"); assertEquals( result.getCitation().getSummary(), expected.getAnnotationCitation().getSummary(), "Returned citation with incorrect summary"); assertEquals( result.getCitation().getNote(), expected.getAnnotationCitation().getNote(), "Returned citation with incorrect note"); if (expected.getAnnotationCitation().getCollaborativeAuthors() != null) { assertEqualsNoOrder( result.getCitation().getCollabAuthors(), expected.getAnnotationCitation().getCollaborativeAuthors().toArray(), "Returned citation with incorrect collab authors"); } else { assertTrue( ArrayUtils.isEmpty(result.getCitation().getCollabAuthors()), "Returned non-empty collab authors when empty was expected"); } if (expected.getAnnotationCitation().getAuthors() != null) { assertNotNull( result.getCitation().getAuthors(), "Returned null authors when authors were expected"); assertEquals( result.getCitation().getAuthors().length, expected.getAnnotationCitation().getAuthors().size(), "Returned incorrect number of authors"); for (int i = 0; i < result.getCitation().getAuthors().length; i++) { AuthorView actualAuthor = result.getCitation().getAuthors()[i]; CorrectedAuthor expectedAuthor = expected.getAnnotationCitation().getAuthors().get(i); assertEquals( actualAuthor.getGivenNames(), expectedAuthor.getGivenNames(), "Author " + (i + 1) + " had incorrect given names"); assertEquals( actualAuthor.getSurnames(), expectedAuthor.getSurName(), "Author " + (i + 1) + " had incorrect surnames"); assertEquals( actualAuthor.getSuffix(), expectedAuthor.getSuffix(), "Author " + (i + 1) + " had incorrect suffix"); } } } }
/** * Get a list of all annotations satisfying the given criteria. * * @param startDate search for annotation after start date. * @param endDate is the date to search until. If null, search until present date * @param annotTypes List of annotation types * @param maxResults the maximum number of results to return, or 0 for no limit * @param journal journalName * @return the (possibly empty) list of article annotations. * @throws ParseException if any of the dates or query could not be parsed * @throws URISyntaxException if an element of annotType cannot be parsed as a URI */ @Override @Transactional(readOnly = true) @SuppressWarnings("unchecked") public List<AnnotationView> getAnnotations( final Date startDate, final Date endDate, final Set<String> annotTypes, final int maxResults, final String journal) throws ParseException, URISyntaxException { /** * * There may be a more efficient way to do this other than querying the database twice, at * some point in time we might improve how hibernate does the object mappings * * <p>This execute returns annotationIDs, article DOIs and titles, which are needed to * construction the annotionView object */ Map<Long, String[]> results = (Map<Long, String[]>) hibernateTemplate.execute( new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException, SQLException { /** * URIGen We have to do this with SQL because of how the mappings are currently * defined And hence, there is no way to unit test this */ StringBuilder sqlQuery = new StringBuilder(); Map<String, Object> params = new HashMap<String, Object>(3); sqlQuery.append("select ann.annotationID, art.doi, art.title "); sqlQuery.append("from annotation ann "); sqlQuery.append("join article art on art.articleID = ann.articleID "); sqlQuery.append("join journal j on art.eIssn = j.eIssn "); sqlQuery.append("where j.journalKey = :journal "); params.put("journal", journal); if (startDate != null) { sqlQuery.append(" and ann.created > :startDate"); params.put("startDate", startDate); } if (endDate != null) { sqlQuery.append(" and ann.created < :endDate"); params.put("endDate", endDate); } if (annotTypes != null) { sqlQuery.append(" and ann.type in (:annotTypes)"); params.put("annotTypes", annotTypes); } sqlQuery.append(" order by ann.created desc"); SQLQuery query = session.createSQLQuery(sqlQuery.toString()); query.setProperties(params); if (maxResults > 0) { query.setMaxResults(maxResults); } List<Object[]> tempResults = query.list(); Map<Long, String[]> results = new HashMap<Long, String[]>(tempResults.size()); for (Object[] obj : tempResults) { // This forces this method to return Long values and not BigInteger results.put( (((Number) obj[0]).longValue()), new String[] {(String) obj[1], (String) obj[2]}); } return results; } }); // The previous query puts annotationID and doi into the map. annotationID is key // I do this to avoid extra doi lookups later in the code. if (results.size() > 0) { DetachedCriteria criteria = DetachedCriteria.forClass(Annotation.class) .add(Restrictions.in("ID", results.keySet())) .addOrder(Order.desc("created")) .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); List<Annotation> annotations = hibernateTemplate.findByCriteria(criteria); List<AnnotationView> views = new ArrayList<AnnotationView>(annotations.size()); for (Annotation ann : annotations) { String articleDoi = results.get(ann.getID())[0]; String articleTitle = results.get(ann.getID())[1]; views.add(buildAnnotationView(ann, articleDoi, articleTitle, false)); } return views; } else { return new ArrayList<AnnotationView>(); } }