Changeset 7613
- Timestamp:
- 04/17/09 16:42:43 (16 months ago)
- Location:
- head/ambra
- Files:
-
- 4 added
- 15 modified
- 5 moved
-
libs/otm-models/src/main/java/org/topazproject/ambra/models/AnnotationBlob.java (modified) (1 diff)
-
libs/otm-models/src/main/java/org/topazproject/ambra/models/ByteArrayBlob.java (moved) (moved from head/ambra/libs/otm-models/src/main/java/org/topazproject/ambra/models/UnmanagedBlob.java) (3 diffs)
-
libs/otm-models/src/main/java/org/topazproject/ambra/models/ReplyBlob.java (modified) (1 diff)
-
libs/otm-models/src/main/java/org/topazproject/ambra/models/Representation.java (modified) (2 diffs)
-
libs/otm-models/src/main/java/org/topazproject/ambra/models/StreamedBlob.java (moved) (moved from head/ambra/libs/otm-models/src/main/java/org/topazproject/ambra/models/Blob.java) (4 diffs)
-
libs/otm-models/src/test/java/org/topazproject/ambra/models/ModelsTest.java (modified) (1 diff)
-
webapp/src/main/java/org/topazproject/ambra/annotation/service/AnnotationConverter.java (modified) (6 diffs)
-
webapp/src/main/java/org/topazproject/ambra/annotation/service/AnnotationService.java (modified) (7 diffs)
-
webapp/src/main/java/org/topazproject/ambra/annotation/service/BaseAnnotation.java (modified) (3 diffs)
-
webapp/src/main/java/org/topazproject/ambra/annotation/service/ReplyService.java (modified) (6 diffs)
-
webapp/src/main/java/org/topazproject/ambra/annotation/service/WebAnnotation.java (modified) (2 diffs)
-
webapp/src/main/java/org/topazproject/ambra/annotation/service/WebReply.java (modified) (2 diffs)
-
webapp/src/main/java/org/topazproject/ambra/feed (added)
-
webapp/src/main/java/org/topazproject/ambra/feed/action (added)
-
webapp/src/main/java/org/topazproject/ambra/feed/action/FeedAction.java (moved) (moved from head/ambra/webapp/src/main/java/org/topazproject/ambra/article/action/ArticleFeed.java) (9 diffs, 1 prop)
-
webapp/src/main/java/org/topazproject/ambra/feed/service (added)
-
webapp/src/main/java/org/topazproject/ambra/feed/service/AnnotationFeedCacheKey.java (added)
-
webapp/src/main/java/org/topazproject/ambra/feed/service/ArticleFeedCacheKey.java (moved) (moved from head/ambra/webapp/src/main/java/org/topazproject/ambra/article/service/FeedCacheKey.java) (10 diffs, 1 prop)
-
webapp/src/main/java/org/topazproject/ambra/feed/service/FeedService.java (moved) (moved from head/ambra/webapp/src/main/java/org/topazproject/ambra/article/service/ArticleFeedService.java) (26 diffs)
-
webapp/src/main/java/org/topazproject/ambra/struts2/AmbraFeedResult.java (modified) (26 diffs)
-
webapp/src/main/resources/struts.xml (modified) (1 diff)
-
webapp/src/main/webapp/discussion/threaded_replies.ftl (modified) (3 diffs)
-
webapp/src/main/webapp/WEB-INF/applicationContext.xml (modified) (1 diff)
-
webapp/src/test/java/org/topazproject/ambra/annotation/service/AnnotationServiceTest.java (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
head/ambra/libs/otm-models/src/main/java/org/topazproject/ambra/models/AnnotationBlob.java
r7611 r7613 30 30 */ 31 31 @Entity() 32 public class AnnotationBlob extends UnmanagedBlob implements CompetingInterest {32 public class AnnotationBlob extends ByteArrayBlob implements CompetingInterest { 33 33 private static final long serialVersionUID = 6834878451274759551L; 34 34 private String id; -
head/ambra/libs/otm-models/src/main/java/org/topazproject/ambra/models/ByteArrayBlob.java
r7611 r7613 32 32 */ 33 33 @Entity() 34 public abstract class UnmanagedBlob implements Serializable {34 public abstract class ByteArrayBlob implements Serializable { 35 35 private static final long serialVersionUID = -783693796375733488L; 36 36 … … 40 40 * Creates a new Blob object. 41 41 */ 42 public UnmanagedBlob() {42 public ByteArrayBlob() { 43 43 } 44 44 … … 48 48 * @param contentType the content type 49 49 */ 50 public UnmanagedBlob(String contentType) {50 public ByteArrayBlob(String contentType) { 51 51 // FIXME: contentType 52 52 } -
head/ambra/libs/otm-models/src/main/java/org/topazproject/ambra/models/ReplyBlob.java
r7611 r7613 30 30 */ 31 31 @Entity() 32 public class ReplyBlob extends UnmanagedBlob implements CompetingInterest {32 public class ReplyBlob extends ByteArrayBlob implements CompetingInterest { 33 33 private static final long serialVersionUID = -1561876836328885263L; 34 34 private String id; -
head/ambra/libs/otm-models/src/main/java/org/topazproject/ambra/models/Representation.java
r7193 r7613 2 2 * $Id$ 3 3 * 4 * Copyright (c) 2006-200 8by Topaz, Inc.4 * Copyright (c) 2006-2009 by Topaz, Inc. 5 5 * http://topazproject.org 6 6 * … … 37 37 */ 38 38 @Entity(graph = "ri", types = {"topaz:Representation"}) 39 public class Representation extends Blob implements PostLoadEventListener, PreInsertEventListener { 39 public class Representation extends StreamedBlob 40 implements PostLoadEventListener, PreInsertEventListener { 40 41 private static final long serialVersionUID = 8927830952382002736L; 41 42 -
head/ambra/libs/otm-models/src/main/java/org/topazproject/ambra/models/StreamedBlob.java
r7193 r7613 2 2 * $Id$ 3 3 * 4 * Copyright (c) 2007-200 8by Topaz, Inc.4 * Copyright (c) 2007-2009 by Topaz, Inc. 5 5 * http://topazproject.org 6 6 * … … 24 24 25 25 /** 26 * Base class for blobs loaded from the BlobStore. 26 * Base class for blobs loaded from the BlobStore. Blob content is not loaded but accessed through 27 * input and output streams. 27 28 * 28 29 * @author Pradeep Krishnan 29 30 */ 30 31 @Entity() 31 public abstract class Blob implements Serializable {32 public abstract class StreamedBlob implements Serializable { 32 33 private static final long serialVersionUID = -783693796375733488L; 33 34 … … 37 38 * Creates a new Blob object. 38 39 */ 39 public Blob() {40 public StreamedBlob() { 40 41 } 41 42 … … 45 46 * @param contentType the content type 46 47 */ 47 public Blob(String contentType) {48 public StreamedBlob(String contentType) { 48 49 // FIXME: contentType 49 50 } -
head/ambra/libs/otm-models/src/test/java/org/topazproject/ambra/models/ModelsTest.java
r7298 r7613 56 56 UserPreferences.class, UserProfile.class, UserRole.class, Journal.class, Issue.class, 57 57 Aggregation.class, EditorialBoard.class, Correction.class, FormalCorrection.class, 58 Retraction.class, Blob.class, ReplyBlob.class, AnnotationBlob.class58 Retraction.class, StreamedBlob.class, ReplyBlob.class, AnnotationBlob.class 59 59 }; 60 60 -
head/ambra/webapp/src/main/java/org/topazproject/ambra/annotation/service/AnnotationConverter.java
r7611 r7613 29 29 30 30 import org.springframework.transaction.annotation.Transactional; 31 import org.springframework.beans.factory.annotation.Required; 31 32 32 33 import org.topazproject.ambra.annotation.Commentary; 33 34 import org.topazproject.ambra.models.Annotea; 34 35 import org.topazproject.ambra.models.ArticleAnnotation; 35 import org.topazproject.ambra.models. UnmanagedBlob;36 import org.topazproject.ambra.models.ByteArrayBlob; 36 37 import org.topazproject.ambra.models.Reply; 37 38 import org.topazproject.ambra.user.service.UserService; … … 40 41 41 42 /** 42 * A kind ofutility class to convert types between topaz and ambra types for43 * A utility class to convert types between topaz and ambra types for 43 44 * Annotations and Replies 44 45 */ … … 66 67 67 68 /** 68 * Converts and <code>ArticleAnnotation</code> to <code>List<Web annotation></code>69 * Converts and <code>ArticleAnnotation</code> to <code>List<WebAnnotation></code> 69 70 * 70 71 * @param annotations an list of annotations … … 84 85 85 86 return wa; 87 } 88 89 /** 90 * Converts and <code>Reply</code> to <code>List<WebReply></code> 91 * 92 * @param replies an list of replies 93 * @param needCreatorName indicates if a display-name of the creator needs to be fetched 94 * @param needBody indicates if the annotation body is required 95 * @return an array of Annotation objects as required by the web layer 96 */ 97 @Transactional(readOnly = true) 98 public List<WebReply> convertReplies(final List<Reply> replies, 99 boolean needCreatorName, 100 boolean needBody) { 101 final List<WebReply> wr = new ArrayList<WebReply>(); 102 103 for (Reply reply : replies) { 104 if (reply != null) 105 wr.add(convert(reply, needCreatorName, needBody)); 106 } 107 108 return wr; 86 109 } 87 110 … … 117 140 return new WebAnnotation(annotation, creator, body); 118 141 } 142 119 143 /** 120 144 * Creates a hierarchical array of replies based on the flat array passed in. … … 208 232 209 233 /** 210 * @return Returns the userService.211 */212 protected UserService getUserService() {213 return userService;214 }215 216 /**217 234 * @param userService The userService to set. 218 235 */ 236 @Required 219 237 public void setUserService(UserService userService) { 220 238 this.userService = userService; 221 239 } 222 240 223 private String loadBody(final Annotea<? extends UnmanagedBlob> annotea)241 private String loadBody(final Annotea<? extends ByteArrayBlob> annotea) 224 242 throws OtmException, Error { 225 243 226 UnmanagedBlob blob = annotea.getBody();244 ByteArrayBlob blob = annotea.getBody(); 227 245 try { 228 246 return (blob == null || blob.getBody() == null) ? "" : new String(blob.getBody(), "UTF-8"); -
head/ambra/webapp/src/main/java/org/topazproject/ambra/annotation/service/AnnotationService.java
r7611 r7613 140 140 AnnotationBlob blob = new AnnotationBlob(contentType); 141 141 blob.setCIStatement(ciStatement); 142 blob.setBody(body.getBytes(getEncodingCharset())); 142 143 143 144 final ArticleAnnotation annotation = annotationClass.newInstance(); … … 153 154 String newId = session.saveOrUpdate(annotation); 154 155 // now that the blob is created by OTM, write to it 155 blob.setBody(body.getBytes(getEncodingCharset()));156 156 157 157 if (log.isDebugEnabled()) … … 316 316 317 317 /** 318 * Get all annotations satisfying the criteria.319 *320 * @param articleId limits the list to annotations from a particular article.321 * @param startDate is the date to start searching from. If null, start from begining of time.322 * Can be iso8601 formatted or string representation of Date object.323 * @param endDate is the date to search until. If null, search until present date324 * @param mediator the mediator of the annotation.325 * @param annotType a filter list of rdf types for the annotations.326 * @param states array of states to filter on327 * @param ascending controls the sort order (by date).328 * @param maxResults the maximum number of results to return, or 0 for no limit329 *330 * @return the (possibly empty) list of articles.331 *332 * @throws ParseException if any of the dates or query could not be parsed333 * @throws URISyntaxException if an element of annotType cannot be parsed as a URI334 */335 @Transactional(readOnly = true)336 public List<ArticleAnnotation> getAnnotations(String articleId, Date startDate, Date endDate,337 String mediator, List<String> annotType,338 int[] states, boolean ascending, int maxResults)339 throws ParseException, URISyntaxException {340 List<String> annotationIds = getAnnotationIds(articleId, startDate, endDate, mediator,341 annotType, states, ascending, maxResults);342 343 return getAnnotations(annotationIds);344 }345 346 /**347 318 * Get a list of all annotation Ids satifying the given criteria. All caching is done 348 319 * at the object level by the session. 349 320 * 350 * @param targetId limits annotations to a particlualr target id.351 321 * @param startDate search for annotation after start date. 352 322 * @param endDate is the date to search until. If null, search until present date 353 * @param mediator annotation mediator 354 * @param annotType a filter list of rdf types for the annotations. 355 * @param states the list of annotation states to search for (all states if null or empty) 356 * @param ascending controls the sort order (by date). 323 * @param annotTypes List of annotation types 357 324 * @param maxResults the maximum number of results to return, or 0 for no limit 358 325 * … … 363 330 */ 364 331 @Transactional(readOnly = true) 365 public List<String> getAnnotationIds(String targetId, Date startDate, Date endDate, 366 String mediator, List<String> annotType, int[] states, 367 boolean ascending, int maxResults) 332 public List<String> getAnnotationIds(Date startDate, Date endDate, Set<String> annotTypes, 333 int maxResults) 368 334 throws ParseException, URISyntaxException { 335 336 // create the query, applying parameters 337 Query annotationQuery = getAnnotationQuery(startDate, endDate, annotTypes, maxResults); 338 339 Results annotationResults = annotationQuery.execute(); 340 List<String> res = new ArrayList<String>(); 341 342 while (annotationResults.next()) { 343 URI id = annotationResults.getURI(0); 344 try { 345 // apply access-controls 346 pep.checkAccess(AnnotationsPEP.LIST_ANNOTATIONS, id); 347 res.add(id.toString()); 348 } catch (SecurityException se) { 349 if (log.isDebugEnabled()) 350 log.debug("Filtering URI " + id + " from Annotation list due to PEP SecurityException", se); 351 } 352 } 353 354 return res; 355 } 356 357 358 /** 359 * Get a list of all reply Ids satifying the given criteria. All caching is done 360 * at the object level by the session. 361 * 362 * @param startDate search for replies after start date. 363 * @param endDate is the date to search until. If null, search until present date 364 * @param annotTypes List of annotation types 365 * @param maxResults the maximum number of results to return, or 0 for no limit 366 * 367 * @return the (possibly empty) list of article ids. 368 * 369 * @throws ParseException if any of the dates or query could not be parsed 370 * @throws URISyntaxException if an element of annotType cannot be parsed as a URI 371 */ 372 @Transactional(readOnly = true) 373 public List<String> getReplyIds(Date startDate, Date endDate, Set<String> annotTypes, int maxResults) 374 throws ParseException, URISyntaxException { 375 376 // create the query, applying parameters 377 Query query = getReplyQuery(startDate, endDate, annotTypes, maxResults); 378 379 Results results = query.execute(); 380 List<String> res = new ArrayList<String>(); 381 382 while (results.next()) { 383 URI id = results.getURI(0); 384 URI annotationId = results.getURI(2); 385 try { 386 // apply access-controls 387 pep.checkAccess(AnnotationsPEP.LIST_ANNOTATIONS, annotationId); 388 res.add(id.toString()); 389 } catch (SecurityException se) { 390 if (log.isDebugEnabled()) 391 log.debug("Filtering reply " + id + " from Annotation list due to PEP SecurityException", se); 392 } 393 } 394 395 return res; 396 } 397 398 private Query getReplyQuery(Date startDate, Date endDate, Set<String> annotTypes, 399 int maxResults) 400 throws URISyntaxException { 401 402 String queryString = createReplyQueryString(startDate, endDate, annotTypes, maxResults); 403 Query query = session.createQuery(queryString); 404 405 bindCommonParams(startDate, endDate, annotTypes, query); 406 return query; 407 } 408 409 private Query getAnnotationQuery(Date startDate, Date endDate, Set<String> annotTypes, 410 int maxResults) 411 throws URISyntaxException { 412 String queryString = createAnnotationQueryString(startDate, endDate, annotTypes, maxResults); 413 Query query = session.createQuery(queryString); 414 415 bindCommonParams(startDate, endDate, annotTypes, query); 416 return query; 417 } 418 419 private void bindCommonParams(Date startDate, Date endDate, Set<String> annotTypes, Query query) 420 throws URISyntaxException { 421 422 if (startDate != null) 423 query.setParameter("sd", startDate); 424 if (endDate != null) 425 query.setParameter("ed", endDate); 426 427 if (annotTypes != null) { 428 int i = 0; 429 for (String type : annotTypes) { 430 query.setUri("type" + i++, URI.create(type)); 431 } 432 } 433 } 434 435 private String createAnnotationQueryString(Date startDate, Date endDate, Set<String> annotTypes, 436 int maxResults) { 437 369 438 StringBuilder qry = new StringBuilder(); 370 439 371 if (targetId != null) { 372 qry.append("select a.id id, cr from Annotation a "); 373 qry.append("where cr := a.created and "); 374 qry.append("a.annotates = :targ "); 375 } else { 376 qry.append("select a.id id, cr from ArticleAnnotation a, Article ar "); 377 qry.append("where a.annotates = ar and cr := a.created "); 378 } 379 380 if (mediator != null) 381 qry.append("and a.mediator = :med "); 382 440 qry.append("select a.id id, cr from ArticleAnnotation a, Article ar "); 441 qry.append("where a.annotates = ar and cr := a.created "); 442 443 appendCommonCriteria(startDate, endDate, annotTypes, maxResults, qry); 444 445 qry.append(';'); 446 447 return qry.toString(); 448 } 449 450 // For now only fetches all Replys 451 private String createReplyQueryString(Date startDate, Date endDate, Set<String> annotTypes, 452 int maxResults) { 453 454 StringBuilder qry = new StringBuilder(); 455 456 qry.append("select r.id id, cr, a.id annid from Reply r, ArticleAnnotation a, Article ar ") 457 .append("where cr := r.created and r.root = a and a.annotates = ar "); 458 459 appendCommonCriteria(startDate, endDate, annotTypes, maxResults, qry); 460 461 qry.append(';'); 462 463 return qry.toString(); 464 } 465 466 private void appendCommonCriteria(Date startDate, Date endDate, Set<String> annotTypes, 467 int maxResults, StringBuilder qry) { 383 468 // apply date constraints 384 469 if (startDate != null) … … 387 472 qry.append("and le(cr, :ed) "); 388 473 389 // match all states 390 if (states != null && states.length > 0) { 474 475 // match all types 476 if (annotTypes != null && annotTypes.size() > 0) { 391 477 qry.append("and ("); 392 for (int i dx = 0; idx < states.length; idx++)393 qry.append("a rt.state = :st").append(idx).append(" or ");478 for (int i = 0; i < annotTypes.size(); i++) 479 qry.append("a.<rdf:type> = :type").append(i).append(" or "); 394 480 qry.setLength(qry.length() - 4); 395 481 qry.append(") "); 396 482 } 397 398 // match all types399 if (annotType != null && annotType.size() > 0) {400 qry.append("and (");401 for (int idx = 0; idx < annotType.size(); idx++)402 qry.append("a.<rdf:type> = :type").append(idx).append(" or ");403 qry.setLength(qry.length() - 4);404 qry.append(") ");405 }406 407 483 // add ordering and limit 408 qry.append("order by cr ").append(ascending ? "asc" : "desc").append(", id asc");484 qry.append("order by cr asc, id asc"); 409 485 410 486 if (maxResults > 0) 411 487 qry.append(" limit ").append(maxResults); 412 413 qry.append(";");414 415 // create the query, applying parameters416 Query q = session.createQuery(qry.toString());417 418 if (targetId != null)419 q.setParameter("targ", targetId);420 if (mediator != null)421 q.setParameter("med", mediator);422 if (startDate != null)423 q.setParameter("sd", startDate);424 if (endDate != null)425 q.setParameter("ed", endDate);426 for (int idx = 0; states != null && idx < states.length; idx++)427 q.setParameter("st" + idx, states[idx]);428 for (int idx = 0; annotType != null && idx < annotType.size(); idx++)429 q.setUri("type" + idx, new URI(annotType.get(idx)));430 431 Results r = q.execute();432 // apply access-controls433 List<String> res = new ArrayList<String>();434 while (r.next()) {435 URI id = r.getURI(0);436 try {437 pep.checkAccess(AnnotationsPEP.LIST_ANNOTATIONS, id);438 res.add(id.toString());439 } catch (SecurityException se) {440 if (log.isDebugEnabled())441 log.debug("Filtering URI " + id + " from Article list due to PEP SecurityException", se);442 }443 }444 return res;445 488 } 446 489 … … 515 558 ArticleAnnotation a = session.get(ArticleAnnotation.class, annotationId); 516 559 if (a == null) 517 throw new IllegalArgumentException("invalid anno ation id: " + annotationId);560 throw new IllegalArgumentException("invalid annotation id: " + annotationId); 518 561 519 562 return a; … … 644 687 * @param mimeType mimeType 645 688 * @param body body 646 * @par em ciStatement competing interesting statement689 * @param ciStatement competing interesting statement 647 690 * @param isPublic isPublic 648 691 * @param user logged in user -
head/ambra/webapp/src/main/java/org/topazproject/ambra/annotation/service/BaseAnnotation.java
r7611 r7613 22 22 23 23 import org.topazproject.ambra.models.Annotea; 24 import org.topazproject.ambra.models. UnmanagedBlob;24 import org.topazproject.ambra.models.ByteArrayBlob; 25 25 import org.topazproject.ambra.util.TextUtils; 26 26 … … 36 36 * @param <T> the Annotea sub-class being delegated to. 37 37 */ 38 public abstract class BaseAnnotation<T extends Annotea<? extends UnmanagedBlob>> {38 public abstract class BaseAnnotation<T extends Annotea<? extends ByteArrayBlob>> { 39 39 /** An integer constant to indicate a unique value for the */ 40 40 private static final int TRUNCATED_COMMENT_LENGTH = 256; … … 204 204 this.originalBodyContent = originalBodyContent; 205 205 } 206 207 public abstract String getCommentTitle(); 208 209 public abstract String getCIStatement(); 206 210 } -
head/ambra/webapp/src/main/java/org/topazproject/ambra/annotation/service/ReplyService.java
r7611 r7613 20 20 21 21 import java.net.URI; 22 import java.net.URISyntaxException; 22 23 import java.util.ArrayList; 23 24 import java.util.Date; 24 25 import java.util.List; 26 import java.util.Set; 27 import java.text.ParseException; 25 28 26 29 import org.apache.commons.logging.Log; … … 49 52 private static final Log log = LogFactory.getLog(ReplyService.class); 50 53 54 private AnnotationService annotationService; // Annotation service Spring injected. 51 55 private RepliesPEP pep; 52 56 private String defaultType; … … 62 66 public void setRepliesPdp(PDP pdp) { 63 67 this.pep = new RepliesPEP(pdp); 68 } 69 70 @Required 71 public void setAnnotationService(AnnotationService annotationService) { 72 this.annotationService = annotationService; 64 73 } 65 74 … … 91 100 ReplyBlob blob = new ReplyBlob(contentType); 92 101 blob.setCIStatement(ciStatement); 102 blob.setBody(body.getBytes(getEncodingCharset())); 93 103 94 104 final Reply r = new ReplyThread(); … … 103 113 104 114 String newId = session.saveOrUpdate(r); 105 blob.setBody(body.getBytes(getEncodingCharset()));106 115 107 116 permissionsService.propagatePermissions(newId, new String[] { blob.getId() }); … … 175 184 remove(all, t); 176 185 } 186 187 /** 188 * Get all replies specified by the list of reply ids. 189 * 190 * @param replyIds a list of annotations Ids to retrieve. 191 * 192 * @return the (possibly empty) list of replies. 193 * 194 */ 195 @Transactional(readOnly = true) 196 public List<Reply> getReplies(List<String> replyIds) { 197 List<Reply> replies = new ArrayList<Reply>(); 198 199 for (String id : replyIds) { 200 try { 201 replies.add(getReply(id)); 202 } catch (IllegalArgumentException iae) { 203 if (log.isDebugEnabled()) 204 log.debug("Ignored illegal reply id:" + id); 205 } catch (SecurityException se) { 206 if (log.isDebugEnabled()) 207 log.debug("Filtering URI " + id + " from Reply list due to PEP SecurityException", se); 208 } 209 } 210 return replies; 211 } 212 213 /** 214 * Get all replies satisfying the criteria. 215 * 216 * @param startDate is the date to start searching from. If null, start from begining of time. 217 * Can be iso8601 formatted or string representation of Date object. 218 * @param endDate is the date to search until. If null, search until present date 219 * @param annotType a filter list of rdf types for the annotations. 220 * @param maxResults the maximum number of results to return, or 0 for no limit 221 * 222 * @return the (possibly empty) list of replies. 223 * 224 * @throws java.text.ParseException if any of the dates or query could not be parsed 225 * @throws java.net.URISyntaxException if an element of annotType cannot be parsed as a URI 226 */ 227 @Transactional(readOnly = true) 228 public List<Reply> getReplies(Date startDate, Date endDate, Set<String> annotType, int maxResults) 229 throws ParseException, URISyntaxException { 230 List<String> replyIds = annotationService.getReplyIds(startDate, endDate, annotType, maxResults); 231 return getReplies(replyIds); 232 } 233 234 177 235 178 236 /** -
head/ambra/webapp/src/main/java/org/topazproject/ambra/annotation/service/WebAnnotation.java
r7420 r7613 75 75 * @return title as String. 76 76 */ 77 @Override 77 78 public String getCommentTitle() { 78 79 String title; … … 124 125 * @return CIStatement as String. 125 126 */ 127 @Override 126 128 public String getCIStatement() { 127 129 AnnotationBlob b = annotea.getBody(); -
head/ambra/webapp/src/main/java/org/topazproject/ambra/annotation/service/WebReply.java
r7368 r7613 67 67 * @return title as String. 68 68 */ 69 @Override 69 70 public String getCommentTitle() { 70 71 return escapeText(annotea.getTitle()); … … 90 91 * @return CIStatement as String. 91 92 */ 93 @Override 92 94 public String getCIStatement() { 93 95 ReplyBlob r = annotea.getBody(); -
head/ambra/webapp/src/main/java/org/topazproject/ambra/feed/action/FeedAction.java
r7603 r7613 2 2 * $Id$ 3 3 * 4 * Copyright (c) 2006-200 7by Topaz, Inc.4 * Copyright (c) 2006-2009 by Topaz, Inc. 5 5 * http://topazproject.org 6 6 * … … 18 18 */ 19 19 20 package org.topazproject.ambra. article.action;20 package org.topazproject.ambra.feed.action; 21 21 22 22 import java.util.List; 23 import java.util.ArrayList;24 23 25 24 import org.apache.commons.logging.Log; … … 27 26 28 27 import org.springframework.transaction.annotation.Transactional; 28 import org.springframework.beans.factory.annotation.Required; 29 29 30 30 import org.topazproject.ambra.action.BaseActionSupport; 31 import org.topazproject.ambra.article.service.ArticleFeedService; 32 import org.topazproject.ambra.article.service.FeedCacheKey; 33 import org.topazproject.ambra.article.service.ArticleFeedService.FEED_TYPES; 31 import org.topazproject.ambra.feed.service.FeedService; 32 import org.topazproject.ambra.feed.service.ArticleFeedCacheKey; 33 import org.topazproject.ambra.feed.service.FeedService.FEED_TYPES; 34 import org.topazproject.ambra.feed.service.AnnotationFeedCacheKey; 34 35 35 36 import com.opensymphony.xwork2.ModelDriven; … … 91 92 * maxResults Integer No 30 The maximun number of result to return. 92 93 * type String No Article Article,Annotation,FormalCorrectionAnnot 93 * MinorCorrectionAnnot,CommentAnnot,Issue 94 * MinorCorrectionAnnot,RetractionAnnot, 95 * CommentAnnot,Issue 94 96 * </pre> 95 97 * 96 * @see org.topazproject.ambra. article.service.FeedCacheKey98 * @see org.topazproject.ambra.feed.service.ArticleFeedCacheKey 97 99 * @see org.topazproject.ambra.struts2.AmbraFeedResult 98 100 * … … 101 103 */ 102 104 @SuppressWarnings("UnusedDeclaration") 103 public class ArticleFeed extends BaseActionSupport implements ModelDriven { 104 private static final Log log = LogFactory.getLog(ArticleFeed.class); 105 106 //TODO: move these to BaseAction support and standardize on result dispatching. 107 private static final String ATOM_RESULT = "ATOM1_0"; 108 private static final String JSON_RESULT = "json"; 109 110 private ArticleFeedService articleFeedService; // Feed Service Spring injected. 111 private FeedCacheKey cacheKey; // The cache key and action data model 112 private List<String> articleIds; // List of Article IDs; result of search 105 public class FeedAction extends BaseActionSupport implements ModelDriven { 106 private static final Log log = LogFactory.getLog(FeedAction.class); 107 108 private FeedService feedService; // Feed Service Spring injected. 109 private ArticleFeedCacheKey cacheKey; // The cache key and action data model 110 private List<String> articleIds; // List of Article or Annotation IDs; result of search 111 private List<String> replyIds; // List of Reply IDs; result of search 113 112 114 113 /** … … 120 119 @Transactional(readOnly = true) 121 120 public String execute() throws Exception { 122 List<String> annotTypes = new ArrayList<String>();123 121 FEED_TYPES t = cacheKey.feedType(); 124 122 125 123 switch (t) { 126 124 case Annotation : 127 articleIds = articleFeedService.getAnnotationIds(cacheKey, null);128 break;129 125 case FormalCorrectionAnnot : 130 annotTypes.add(t.rdfType()) ;131 articleIds = articleFeedService.getAnnotationIds(cacheKey,annotTypes);132 break;133 126 case MinorCorrectionAnnot : 134 annotTypes.add(t.rdfType()) ;135 articleIds = articleFeedService.getAnnotationIds(cacheKey,annotTypes);136 break;137 case CommentAnnot :138 annotTypes.add(t.rdfType()) ;139 articleIds = articleFeedService.getAnnotationIds(cacheKey,annotTypes);127 case RetractionAnnot: 128 case CommentAnnot : 129 articleIds = feedService.getAnnotationIds( 130 new AnnotationFeedCacheKey(AnnotationFeedCacheKey.Type.ANNOTATIONS, cacheKey)); 131 replyIds = feedService.getReplyIds( 132 new AnnotationFeedCacheKey(AnnotationFeedCacheKey.Type.REPLIES, cacheKey)); 140 133 break; 141 134 case Article : 142 articleIds = articleFeedService.getArticleIds(cacheKey);135 articleIds = feedService.getArticleIds(cacheKey); 143 136 break; 144 137 case Issue : 145 articleIds = articleFeedService.getIssueArticleIds(cacheKey, getCurrentJournal());138 articleIds = feedService.getIssueArticleIds(cacheKey, getCurrentJournal()); 146 139 break; 147 140 } … … 164 157 cacheKey.setJournal(getCurrentJournal()); 165 158 cacheKey.validate(this); 166 } 167 168 /** 169 * Set <code>articleFeedService</code> field to the article Feed service singleton. 170 * 171 * @param articleFeedService the object transaction model reference 172 */ 173 public void setArticleFeedService(final ArticleFeedService articleFeedService) { 174 this.articleFeedService = articleFeedService; 175 } 176 177 /** 178 * This is the results of the query which consist of a list of article ID's. 179 * 180 * @return the list of article ID's returned from the query. 159 if (log.isErrorEnabled()) { 160 161 for (Object key : getFieldErrors().keySet()) { 162 log.error("Validate error: " + getFieldErrors().get(key) + " on " + key + 163 " for cache key: " + cacheKey); 164 } 165 } 166 } 167 168 /** 169 * Set <code>feedService</code> field to the article Feed service singleton. 170 * 171 * @param feedService the object transaction model reference 172 */ 173 @Required 174 public void setFeedService(final FeedService feedService) { 175 this.feedService = feedService; 176 } 177 178 /** 179 * This is the results of the query which consist of a list of article or annotation ID's. 180 * 181 * @return the list of article/annotation ID's returned from the query. 181 182 */ 182 183 public List<String> getIds() { … … 185 186 186 187 /** 188 * This is the results of the query which consist of a list of reply ID's. 189 * 190 * @return the list of reply ID's returned from the query. 191 */ 192 public List<String> getReplyIds() { 193 return replyIds; 194 } 195 196 /** 187 197 * Return the cache key being used by this action. 188 198 * 189 199 * @return Key to the cache which is also the data model of the action 190 200 */ 191 public FeedCacheKey getCacheKey() {201 public ArticleFeedCacheKey getCacheKey() { 192 202 return this.cacheKey; 193 203 } … … 203 213 * Make sure caheKey is not created twice. 204 214 */ 205 return (cacheKey == null) ? cacheKey = articleFeedService.newCacheKey() : cacheKey;215 return (cacheKey == null) ? cacheKey = feedService.newCacheKey() : cacheKey; 206 216 } 207 217 -
head/ambra/webapp/src/main/java/org/topazproject/ambra/feed/service/ArticleFeedCacheKey.java
r7483 r7613 18 18 */ 19 19 20 package org.topazproject.ambra. article.service;20 package org.topazproject.ambra.feed.service; 21 21 22 22 import org.topazproject.ambra.action.BaseActionSupport; … … 27 27 import java.text.ParseException; 28 28 import java.net.URI; 29 import org.topazproject.ambra.article.service.ArticleFeedService.FEED_TYPES;30 29 31 30 /** … … 42 41 * affect the output. 43 42 * 44 * @see org.topazproject.ambra.article.service.ArticleFeedService45 * @see org.topazproject.ambra.article.service.ArticleFeedService.Invalidator46 * @see org.topazproject.ambra.article.service.ArticleFeedService.FEED_TYPES43 * @see FeedService 44 * @see FeedService.Invalidator 45 * @see FeedService.FEED_TYPES 47 46 * @see org.topazproject.ambra.struts2.AmbraFeedResult 48 47 */ 49 public class FeedCacheKey implements Serializable, Comparable {48 public class ArticleFeedCacheKey implements Serializable, Comparable { 50 49 private static final long serialVersionUID = 1L; 51 50 private String journal; … … 64 63 private int maxResults; 65 64 private URI issueURI; 66 private String type = FEED_TYPES.Article.toString();65 private String type; 67 66 68 67 final SimpleDateFormat dateFrmt = new SimpleDateFormat("yyyy-MM-dd"); … … 72 71 * Key Constructor - currently does nothing. 73 72 */ 74 public FeedCacheKey() { 73 public ArticleFeedCacheKey() { 74 type = FeedService.FEED_TYPES.Article.toString(); 75 75 } 76 76 … … 120 120 @Override 121 121 public boolean equals(Object o) { 122 if (o == null || !(o instanceof FeedCacheKey))122 if (o == null || !(o instanceof ArticleFeedCacheKey)) 123 123 return false; 124 FeedCacheKey key = (FeedCacheKey) o; 124 125 if (o == this) 126 return true; 127 128 ArticleFeedCacheKey key = (ArticleFeedCacheKey) o; 125 129 return ( 126 130 key.hashCode == this.hashCode … … 160 164 public String toString() { 161 165 StringBuilder builder = new StringBuilder(); 162 163 builder.append("journal=").append(journal);164 builder.append(";type=").append(type);166 builder.append("ArticleFeedCacheKey{") 167 .append("journal=").append(journal) 168 .append(", type=").append(type); 165 169 166 170 if (sDate != null) 167 builder.append(" ;startDate=").append(sDate);171 builder.append(", startDate=").append(sDate); 168 172 169 173 if (eDate != null) 170 builder.append(" ;endDate=").append(eDate);174 builder.append(", endDate=").append(eDate); 171 175 172 176 if (category != null) 173 builder.append(" ;category=").append(category);177 builder.append(", category=").append(category); 174 178 175 179 if (author != null) 176 builder.append(" ;author=").append(author);180 builder.append(", author=").append(author); 177 181 178 182 if (issueURI != null) 179 builder.append("; issueURIr=").append(issueURI); 180 181 builder.append("; maxResults=").append(maxResults); 183 builder.append(", issueURIr=").append(issueURI); 184 185 builder.append(", maxResults=").append(maxResults) 186 .append('}'); 182 187 183 188 return builder.toString(); … … 210 215 * @param action - the BaseSupportAction allows reporting of field errors. Pass in a reference 211 216 * incase we want to report them. 212 * @see ArticleFeedService217 * @see FeedService 213 218 */ 214 219 @SuppressWarnings("UnusedDeclaration") … … 232 237 233 238 // If there is garbage in the type default to Article 234 if (feedType() == F EED_TYPES.Invalid)235 type = F EED_TYPES.Article.toString();239 if (feedType() == FeedService.FEED_TYPES.Invalid) 240 type = FeedService.FEED_TYPES.Article.toString(); 236 241 237 242 // Need a positive non-zero number of results … … 253 258 * any of the types) 254 259 */ 255 public F EED_TYPES feedType() {256 F EED_TYPES t;260 public FeedService.FEED_TYPES feedType() { 261 FeedService.FEED_TYPES t; 257 262 try { 258 t = F EED_TYPES.valueOf(type);263 t = FeedService.FEED_TYPES.valueOf(type); 259 264 } catch (Exception e) { 260 265 // It's ok just return invalid. 261 t = F EED_TYPES.Invalid;266 t = FeedService.FEED_TYPES.Invalid; 262 267 } 263 268 return t; -
head/ambra/webapp/src/main/java/org/topazproject/ambra/feed/service/FeedService.java
r7603 r7613 17 17 * limitations under the License. 18 18 */ 19 package org.topazproject.ambra. article.service;19 package org.topazproject.ambra.feed.service; 20 20 21 21 import java.net.URI; … … 25 25 import java.util.Date; 26 26 import java.util.List; 27 import java.util.Set;28 27 29 28 import org.apache.commons.logging.Log; … … 44 43 import org.topazproject.ambra.models.RatingSummary; 45 44 import org.topazproject.ambra.models.Reply; 45 import org.topazproject.ambra.models.Retraction; 46 46 import org.topazproject.ambra.annotation.service.AnnotationService; 47 47 import org.topazproject.ambra.annotation.service.AnnotationConverter; 48 48 import org.topazproject.ambra.annotation.service.WebAnnotation; 49 import org.topazproject.ambra.annotation.service.ReplyService; 50 import org.topazproject.ambra.annotation.service.WebReply; 49 51 import org.topazproject.ambra.cache.AbstractObjectListener; 50 52 import org.topazproject.ambra.cache.Cache; … … 53 55 import org.topazproject.ambra.model.article.ArticleInfo; 54 56 import org.topazproject.ambra.article.action.TOCArticleGroup; 57 import org.topazproject.ambra.article.service.ArticleOtmService; 58 import org.topazproject.ambra.article.service.BrowseService; 59 import org.topazproject.ambra.article.service.NoSuchArticleIdException; 55 60 56 61 import org.topazproject.otm.Session; … … 59 64 60 65 /** 61 * The <code> ArticleFeedService</code> supplies the API for querying and caching62 * feed request. <code> ArticleFeedService</code> is a Spring injected singleton66 * The <code>FeedService</code> supplies the API for querying and caching 67 * feed request. <code>FeedService</code> is a Spring injected singleton 63 68 * which coordinates access to the <code>annotationService, articleOtmService</code> 64 69 * and <code>feedCache</code>. 65 70 */ 66 public class ArticleFeedService { 67 private static final Log log = LogFactory.getLog(ArticleFeedService.class); 68 69 private AnnotationService annotationService; // Annotation service Spring injected. 70 private ArticleOtmService articleOtmService; // Article Otm service Spring injected 71 private BrowseService browseService; // Browse Article Servcie Spring Injected 72 private JournalService journalService; // Journal service Spring injected. 73 private Cache feedCache; // Feed Cache Spring injected 74 private Invalidator invalidator; // Cache invalidator 75 private Session session; 71 public class FeedService { 72 private static final Log log = LogFactory.getLog(FeedService.class); 73 74 private AnnotationService annotationService; // Annotation service Spring injected. 75 private ReplyService replyService; // Reply service Spring injected. 76 private ArticleOtmService articleOtmService; // Article Otm service Spring injected 77 private BrowseService browseService; // Browse Article Servcie Spring Injected 78 private JournalService journalService; // Journal service Spring injected. 79 private AnnotationConverter annotationConverter; // Annotation converter 80 private Cache feedCache; // Feed Cache Spring injected 81 private Invalidator invalidator; // Cache invalidator 82 private Session session; 76 83 77 84 /** … … 92 99 MinorCorrectionAnnot { public String rdfType() { return MinorCorrection.RDF_TYPE; } 93 100 public Class isClass() { return MinorCorrection.class; } }, 101 RetractionAnnot { public String rdfType() { return Retraction.RDF_TYPE; } 102 public Class isClass() { return Retraction.class; } }, 94 103 RatingAnnot { public String rdfType() { return Rating.RDF_TYPE; } 95 104 public Class isClass() { return Rating.class; } }, … … 111 120 * Constructor - currently does nothing. 112 121 */ 113 public ArticleFeedService(){122 public FeedService(){ 114 123 } 115 124 … … 119 128 * @return Key a new cache key to be used as a data model for the FeedAction. 120 129 */ 121 public FeedCacheKey newCacheKey() {122 return new FeedCacheKey();130 public ArticleFeedCacheKey newCacheKey() { 131 return new ArticleFeedCacheKey(); 123 132 } 124 133 … … 132 141 * @throws ApplicationException ApplicationException 133 142 */ 134 public List<String> getArticleIds(final FeedCacheKey cacheKey) throws ApplicationException {143 public List<String> getArticleIds(final ArticleFeedCacheKey cacheKey) throws ApplicationException { 135 144 // Create a local lookup based on the feed URI. 136 145 Cache.Lookup<List<String>, ApplicationException> lookUp = … … 147 156 * 148 157 * @param cacheKey is both the feedAction data model and cache key. 158 * @param journal Current journal 149 159 * @return List<String> if article Ids. 150 160 * @throws ApplicationException ApplicationException 151 */ 152 public List<String> getIssueArticleIds(final FeedCacheKey cacheKey, String journal) throws 161 * @throws URISyntaxException URISyntaxException 162 */ 163 public List<String> getIssueArticleIds(final ArticleFeedCacheKey cacheKey, String journal) throws 153 164 URISyntaxException, ApplicationException { 154 165 List<String> articleList = new ArrayList<String>(); … … 181 192 182 193 /** 183 * Returns a list of annotations associated with a particular article.184 *185 * @param targetId limits annotationIds to a particlular target186 * @param annotType a filter list of rdf types for the annotations.187 * @param maxResult maximum number of annotations to return188 * @param needBody boolean specifying whether the body of the annotation is needed189 * @return <code>List<WebAnnotation></code> a list of webannotations that related to the190 * specified article191 * @throws ApplicationException Converts all exceptions to ApplicationException192 */193 public List<WebAnnotation> getAnnotations(final String targetId, List<String> annotType,194 int maxResult, boolean needBody) throws ApplicationException {195 AnnotationConverter converter = new AnnotationConverter();196 List<WebAnnotation> webAnnot;197 198 try {199 List<ArticleAnnotation> annotations = annotationService.getAnnotations(200 targetId, null, null, null,201 annotType, null, true, maxResult);202 webAnnot = converter.convert(annotations,true, needBody);203 } catch (Exception ex) {204 throw new ApplicationException(ex);205 }206 return webAnnot;207 }208 209 /**210 194 * Returns a list of annotation Ids based on parameters contained in 211 * the cache key. If a start date is not specified t jen a default195 * the cache key. If a start date is not specified then a default 212 196 * date is used but not stored in the key. 213 197 * 214 * @param cacheKey is both the feedAction data model and cache key. 215 * @param annotType a filter list of rdf types for the annotations. 198 * @param cacheKey cache key. 216 199 * @return <code>List<String></code> a list of annotation Ids 217 200 * @throws ApplicationException Converts all exceptions to ApplicationException 218 201 */ 219 public List<String> getAnnotationIds(final FeedCacheKey cacheKey, List<String> annotType)202 public List<String> getAnnotationIds(final AnnotationFeedCacheKey cacheKey) 220 203 throws ApplicationException { 204 205 // Create a local lookup based on the feed URI. 206 Cache.Lookup<List<String>, ApplicationException> lookUp = 207 new Cache.SynchronizedLookup<List<String>, ApplicationException>(cacheKey) { 208 public List<String> lookup() throws ApplicationException { 209 return fetchAnnotationIds(cacheKey); 210 } 211 }; 212 // Get articel ID's from the feed cache or add it 213 return feedCache.get(cacheKey, -1, lookUp); 214 } 215 216 /** 217 * Returns a list of reply Ids based on parameters contained in 218 * the cache key. If a start date is not specified then a default 219 * date is used but not stored in the key. 220 * 221 * @param cacheKey cache key 222 * @return <code>List<String></code> a list of reply Ids 223 * @throws ApplicationException Converts all exceptions to ApplicationException 224 */ 225 public List<String> getReplyIds(final AnnotationFeedCacheKey cacheKey) 226 throws ApplicationException { 227 228 // Create a local lookup based on the feed URI. 229 Cache.Lookup<List<String>, ApplicationException> lookUp = 230 new Cache.SynchronizedLookup<List<String>, ApplicationException>(cacheKey) { 231 public List<String> lookup() throws ApplicationException { 232 return fetchReplyIds(cacheKey); 233 } 234 }; 235 // Get articel ID's from the feed cache or add it 236 return feedCache.get(cacheKey, -1, lookUp); 237 } 238 239 private List<String> fetchAnnotationIds(final AnnotationFeedCacheKey cacheKey) 240 throws ApplicationException { 241 221 242 List<String> annotIds; 222 243 try { 223 244 annotIds = annotationService.getAnnotationIds( 224 null, cacheKey.getSDate(), cacheKey.getEDate(),225 null, annotType, null, true,cacheKey.getMaxResults());245 cacheKey.getStartDate(), cacheKey.getEndDate(), cacheKey.getAnnotationTypes(), 246 cacheKey.getMaxResults()); 226 247 227 248 } catch (Exception ex) { … … 231 252 } 232 253 233 /** 234 * Returns a list of annotations which meet the criteria set by parameters in 235 * the cache key. 236 * 237 * @param cacheKey is both the feedAction data model and cache key. 238 * @param annotType a filter list of rdf types for the annotations. 239 * @return <code>List<WebAnnotation></code> a list of webannotations that related to the 240 * specified article 241 * @throws ApplicationException Converts all exceptions to ApplicationException 242 */ 243 // FIXME: Dead code - Method is not used anywhere 244 public List<WebAnnotation> getAnnotations(final FeedCacheKey cacheKey, List<String> annotType) 254 private List<String> fetchReplyIds(final AnnotationFeedCacheKey cacheKey) 245 255 throws ApplicationException { 246 AnnotationConverter converter = new AnnotationConverter(); 247 List<WebAnnotation> webAnnot; 248 256 257 List<String> replyIds; 249 258 try { 250 List<ArticleAnnotation> annotations = annotationService.getAnnotations(251 null, cacheKey.getSDate(), cacheKey.getEDate(),252 null, annotType, null, true,cacheKey.getMaxResults());253 webAnnot = converter.convert(annotations,true,true); 259 replyIds = annotationService.getReplyIds( 260 cacheKey.getStartDate(), cacheKey.getEndDate(), cacheKey.getAnnotationTypes(), 261 cacheKey.getMaxResults()); 262 254 263 } catch (Exception ex) { 255 264 throw new ApplicationException(ex); 256 265 } 257 return webAnnot;266 return replyIds; 258 267 } 259 268 … … 269 278 public List<WebAnnotation> getAnnotations(final List<String> annotIds) 270 279 throws ApplicationException { 271 AnnotationConverter converter = new AnnotationConverter();272 280 List<WebAnnotation> webAnnot; 273 281 274 282 try { 275 283 List<ArticleAnnotation> annotations = annotationService.getAnnotations(annotIds); 276 webAnnot = converter.convert(annotations,true,true);284 webAnnot = annotationConverter.convert(annotations,true,true); 277 285 } catch (Exception ex) { 278 286 throw new ApplicationException(ex); 279 287 } 280 288 return webAnnot; 289 } 290 291 /** 292 * Returns a list of replies associated with a particular list 293 * annotation Ids. 294 * 295 * @param replyIds a list of reply Ids to retrieve. 296 * @return <code>List<WebReply></code> a list of webareplies 297 * with the specified Ids. 298 * @throws ApplicationException Converts all exceptions to ApplicationException 299 */ 300 public List<WebReply> getReplies(final List<String> replyIds) 301 throws ApplicationException { 302 303 List<WebReply> webReplies; 304 305 try { 306 List<Reply> replies = replyService.getReplies(replyIds); 307 webReplies = annotationConverter.convertReplies(replies,true,true); 308 } catch (Exception ex) { 309 throw new ApplicationException(ex); 310 } 311 return webReplies; 281 312 } 282 313 … … 289 320 * @throws ApplicationException Converts all exceptions to ApplicationException 290 321 */ 291 private List<String> fetchArticleIds(final FeedCacheKey cacheKey) throws ApplicationException {322 private List<String> fetchArticleIds(final ArticleFeedCacheKey cacheKey) throws ApplicationException { 292 323 List<String> categoriesList = new ArrayList<String>(); 293 324 if (cacheKey.getCategory() != null && cacheKey.getCategory().length() > 0) { … … 348 379 349 380 /** 381 * @param replyService Reply Service 382 */ 383 @Required 384 public void setReplyService(ReplyService replyService) { 385 this.replyService = replyService; 386 } 387 388 /** 350 389 * @param browseService Browse Service 351 390 */ … … 355 394 this.browseService = browseService; 356 395 } 396 397 /** 398 * @param annotationConverter Annotation converter 399 */ 400 @Required 401 public void setAnnotationConverter(AnnotationConverter annotationConverter) { 402 this.annotationConverter = annotationConverter; 403 } 404 405 357 406 358 407 /** … … 405 454 * then remove that cache entry. 406 455 * 407 * @see ArticleFeedService456 * @see FeedService 408 457 */ 409 458 public class Invalidator extends AbstractObjectListener { … … 427 476 } else if (object instanceof Journal) { 428 477 invalidateFeedCacheForJournal((Journal)object, updates); 478 } else if (object instanceof ArticleAnnotation) { 479 invalidateFeedCacheForAnnotation((ArticleAnnotation)object); 480 } else if (object instanceof Reply) { 481 invalidateFeedCacheForReply((Reply)object); 429 482 } 430 483 } … … 444 497 throws Exception { 445 498 // If this is an Active Article check to see if it invalidates the feed cache 446 if (object instanceof Article && ((Article) object).getState() == Article.STATE_ACTIVE) 447 invalidateFeedCacheForArticle((Article)object); 499 if (object instanceof Article && ((Article) object).getState() == Article.STATE_ACTIVE) { 500 invalidateFeedCacheForArticle((Article) object); 501 } else if (object instanceof ArticleAnnotation) { 502 invalidateFeedCacheForAnnotation((ArticleAnnotation) object); 503 } else if (object instanceof Reply) { 504 invalidateFeedCacheForReply((Reply) object); 505 } 448 506 } 449 507 … … 474 532 * @param article the article which might change the cash. 475 533 */ 476 @SuppressWarnings("unchecked")477 534 private void invalidateFeedCacheForArticle(Article article) { 478 for (FeedCacheKey key : (Set<FeedCacheKey>) feedCache.getKeys()) { 479 if (matches(key, article, true)) 480 feedCache.remove(key); 535 536 for (Object key : feedCache.getKeys()) { 537 if (key instanceof ArticleFeedCacheKey) { 538 if (matchesArticle((ArticleFeedCacheKey) key, article)) 539 feedCache.remove(key); 540 } else if (key instanceof AnnotationFeedCacheKey) { 541 if(matchesJournal(article, ((AnnotationFeedCacheKey)key).getJournal())) 542 feedCache.remove(key); 543 } 481 544 } 482 545 } … … 488 551 * @param journal the journal of interest 489 552 */ 490 @SuppressWarnings("unchecked")491 553 private void invalidateFeedCacheForJournalArticle(Journal journal) { 492 for (FeedCacheKey key : (Set<FeedCacheKey>) feedCache.getKeys()) { 493 if (key.getJournal().equals(journal.getKey())) { 494 feedCache.remove(key); 495 } 496 } 497 } 554 for (Object key : feedCache.getKeys()) { 555 if (key instanceof ArticleFeedCacheKey) { 556 if (((ArticleFeedCacheKey) key).getJournal().equals(journal.getKey())) 557 feedCache.remove(key); 558 } else if (key instanceof AnnotationFeedCacheKey) { 559 if (((AnnotationFeedCacheKey)key).getJournal().equals(journal.getKey())) 560 feedCache.remove(key); 561 } 562 } 563 } 564 565 /** 566 * Invalidate the cache entries based on a article annotation. 567 * 568 * @param annotation The annotation. 569 */ 570 private void invalidateFeedCacheForAnnotation(ArticleAnnotation annotation) { 571 for (Object key : feedCache.getKeys()) { 572 if (key instanceof AnnotationFeedCacheKey) { 573 if (matchesAnnotation((AnnotationFeedCacheKey)key, annotation)) 574 feedCache.remove(key); 575 } 576 } 577 } 578 579 580 /** 581 * Invalidate the cache entries based on a annotation reply. 582 * 583 * @param reply The reply. 584 */ 585 private void invalidateFeedCacheForReply(Reply reply) { 586 for (Object key : feedCache.getKeys()) { 587 if (key instanceof AnnotationFeedCacheKey) { 588 AnnotationFeedCacheKey annotationKey = (AnnotationFeedCacheKey) key; 589 if (matchesReply(annotationKey, reply)) 590 feedCache.remove(key); 591 } 592 } 593 } 594 595 596 498 597 499 598 /** … … 527 626 * @param key the cache key and input parameters 528 627 * @param article article that has caused the change 529 * @param checkJournal include journal as part of match if true.530 628 * @return boolean true if we need to remove this entry from the cache 531 629 */ 532 private boolean matches (FeedCacheKey key, Article article, boolean checkJournal) {533 if ( checkJournal && !matchesJournal(key, article))630 private boolean matchesArticle(ArticleFeedCacheKey key, Article article) { 631 if (!matchesJournal(article, key.getJournal())) 534 632 return false; 535 633 536 634 DublinCore dc = article.getDublinCore(); 537 538 if (!matchesDates(key, dc)) 635 636 return matchesDates(dc.getDate(), key.getSDate(), key.getEDate()) && 637 matchesCategory(key, article) && 638 matchesAuthor(key, dc); 639 640 } 641 642 private boolean matchesAnnotation(AnnotationFeedCacheKey key, ArticleAnnotation annotation) { 643 try { 644 Article article = articleOtmService.getArticle(annotation.getAnnotates()); 645 if (!matchesJournal(article, key.getJournal())) 646 return false; 647 648 } catch (NoSuchArticleIdException e) { 649 log.error("Failed trying to invalidate FeedCache for annotation " + annotation.getId() + 650 " and key " + key.toString(), e); 651 return true; // remove this cache entry 652 } 653 654 return matchesDates(annotation.getCreated(), key.getStartDate(), key.getEndDate()) && 655 matchesAnnotationType(key, annotation); 656 657 } 658 659 660 private boolean matchesReply(AnnotationFeedCacheKey key, Reply reply) { 661 662 if (key.getType() != AnnotationFeedCacheKey.Type.REPLIES) 539 663 return false; 540 664 541 return (!matchesCategory(key, article) && !matchesAuthor(key, dc)); 542 543 } 665 ArticleAnnotation annotation = annotationService.getAnnotation(reply.getRoot()); 666 if (annotation != null) { 667 try { 668 Article article = articleOtmService.getArticle(annotation.getAnnotates()); 669 if (!matchesJournal(article, key.getJournal())) 670 return false; 671 } catch (NoSuchArticleIdException e) { 672 log.error("Failed trying to invalidate FeedCache for reply " + reply.getId() + 673 " and key " + key.toString(), e); 674 return true; // remove this cache entry 675 } 676 677 if (!matchesAnnotationType(key, annotation)) 678 return false; 679 680 } else { 681 log.error("Root annotation not found for reply " + reply.getId()); 682 return true; // remove this cache entry 683 } 684 685 return matchesDates(reply.getCreated(), key.getStartDate(), key.getEndDate()); 686 687 } 688 544 689 545 690 /** … … 553 698 * @return boolean true if there is a match 554 699 */ 555 private boolean matchesAuthor( FeedCacheKey key, DublinCore dc) {700 private boolean matchesAuthor(ArticleFeedCacheKey key, DublinCore dc) { 556 701 boolean matches = false; 557 702 … … 580 725 * @return boolean true if the category matches (key.category = null is wildcard) 581 726 */ 582 private boolean matchesCategory( FeedCacheKey key, Article article) {727 private boolean matchesCategory(ArticleFeedCacheKey key, Article article) { 583 728 boolean matches = false; 584 729 … … 596 741 } 597 742 743 private boolean matchesAnnotationType(AnnotationFeedCacheKey key, ArticleAnnotation annotation) { 744 745 return key.getAnnotationTypes() == null || 746 key.getAnnotationTypes().size() == 0 || 747 key.getAnnotationTypes().contains(FEED_TYPES.Annotation.rdfType()) || 748 annotation instanceof FormalCorrection && 749 key.getAnnotationTypes().contains(FEED_TYPES.FormalCorrectionAnnot.rdfType()) || 750 annotation instanceof MinorCorrection && 751 key.getAnnotationTypes().contains(FEED_TYPES.MinorCorrectionAnnot.rdfType()) || 752 annotation instanceof Comment && 753 key.getAnnotationTypes().contains(FEED_TYPES.CommentAnnot.rdfType()) || 754 annotation instanceof Retraction && 755 key.getAnnotationTypes().contains(FEED_TYPES.RetractionAnnot.rdfType()); 756 757 } 758 759 598 760 /** 599 761 * Check to see if the article date is between the start and end date specified in the key. If 600 762 * it is then return true and the entry for this key should be removed. 601 763 * 602 * @param key cache key603 * @param dc Dublincore field from the article604 * 764 * @param createDate date object is created 765 * @param startDate Start date, can be null. 766 * @param endDate End date can be null. 605 767 * @return boolean true if the article date falls between the start and end date 606 768 */ 607 private boolean matchesDates( FeedCacheKey key, DublinCore dc) {608 Date articleDate = dc.getDate(); 769 private boolean matchesDates(Date createDate, Date startDate, Date endDate) { 770 609 771 boolean matches = false; 610 772 611 773 // If start and end are null then it doesn't matter what the article date is. 612 if (( key.getEDate() == null) && (key.getSDate()== null)) {774 if ((endDate == null) && (startDate == null)) { 613 775 matches = true; 614 } else if ( articleDate != null) {615 if (( key.getEDate() == null) && articleDate.after(key.getSDate())) {776 } else if (createDate != null) { 777 if ((endDate == null) && createDate.after(startDate)) { 616 778 matches = true; 617 } else if (( key.getSDate() == null) && articleDate.before(key.getEDate())) {779 } else if ((startDate == null) && createDate.before(endDate)) { 618 780 matches = true; 619 } else if ( articleDate.after(key.getSDate()) && articleDate.before(key.getEDate())) {781 } else if (createDate.after(startDate) && createDate.before(endDate)) { 620 782 matches = true; 621 783 } … … 628 790 * journals the article belongs to. 629 791 * 630 * @param key a cache key and actiopn data model631 792 * @param article the article 793 * @param journalKey Journal 632 794 * @return boolean true if key.journal matches one of the journals returned 633 795 * by the journal service. 634 796 */ 635 private boolean matchesJournal( FeedCacheKey key, Article article) {797 private boolean matchesJournal(Article article, String journalKey) { 636 798 boolean matches = false; 637 799 638 if ( key.getJournal()!= null) {800 if (journalKey != null) { 639 801 for (Journal journal : journalService.getJournalsForObject(article.getId())) { 640 if (journal.getKey().equals( key.getJournal())) {802 if (journal.getKey().equals(journalKey)) { 641 803 matches = true; 642 804 break; -
head/ambra/webapp/src/main/java/org/topazproject/ambra/struts2/AmbraFeedResult.java
r7609 r7613 32 32 import java.util.Date; 33 33 import java.util.Set; 34 import java.util.SortedMap; 35 import java.util.TreeMap; 34 36 35 37 import java.io.Writer; … … 50 52 import org.topazproject.ambra.models.Representation; 51 53 import org.topazproject.ambra.models.UserProfile; 52 import org.topazproject.ambra.article.action.ArticleFeed; 53 import org.topazproject.ambra.article.service.ArticleFeedService; 54 import org.topazproject.ambra.article.service.FeedCacheKey; 55 import org.topazproject.ambra.article.service.ArticleFeedService.FEED_TYPES; 54 import org.topazproject.ambra.feed.service.FeedService; 55 import org.topazproject.ambra.feed.service.ArticleFeedCacheKey; 56 import org.topazproject.ambra.feed.service.FeedService.FEED_TYPES; 56 57 import org.topazproject.ambra.web.VirtualJournalContext; 57 58 import org.topazproject.ambra.configuration.ConfigurationStore; … … 59 60 import org.jdom.Element; 60 61 import org.springframework.transaction.annotation.Transactional; 62 import org.springframework.beans.factory.annotation.Required; 61 63 import org.topazproject.ambra.models.UserAccount; 62 64 import org.topazproject.ambra.annotation.service.WebAnnotation; 65 import org.topazproject.ambra.annotation.service.WebReply; 66 import org.topazproject.ambra.annotation.service.BaseAnnotation; 63 67 import org.topazproject.ambra.ApplicationException; 64 68 import org.topazproject.ambra.model.article.ArticleType; … … 87 91 * </pre> 88 92 * 89 * @see org.topazproject.ambra. article.service.FeedCacheKey90 * @see ArticleFeed93 * @see org.topazproject.ambra.feed.service.ArticleFeedCacheKey 94 * @see org.topazproject.ambra.feed.action.FeedAction 91 95 * 92 96 * @author jsuttor 93 97 */ 94 98 public class AmbraFeedResult extends Feed implements Result { 95 private List<Article> articles; 96 private List<WebAnnotation> annotations; 97 private ArticleFeedService articleFeedService; 99 private FeedService feedService; 98 100 private ArticleXMLUtils articleXmlUtils; 99 101 … … 179 181 @SuppressWarnings("unchecked") 180 182 public void execute(ActionInvocation ai) throws Exception { 183 181 184 HttpServletRequest request = ServletActionContext.getRequest(); 182 185 String pathInfo = request.getPathInfo(); … … 189 192 190 193 // Get the article IDs that were cached by the feed. 191 FeedCacheKey cacheKey = (FeedCacheKey)ai.getStack().findValue("cacheKey"); 192 List<String> articleIds = (List<String>) ai.getStack().findValue("Ids"); 193 FEED_TYPES t = cacheKey.feedType(); 194 195 switch (t) { 196 case Annotation: 197 case FormalCorrectionAnnot: 198 case MinorCorrectionAnnot: 199 case CommentAnnot: 200 annotations = articleFeedService.getAnnotations(articleIds); 201 break; 202 case Article : 203 case Issue : 204 articles = articleFeedService.getArticles(articleIds); 205 break; 206 } 207 208 String xmlBase = (cacheKey.getRelativeLinks() ? "" : JOURNAL_URI); 194 ArticleFeedCacheKey cacheKey = (ArticleFeedCacheKey)ai.getStack().findValue("cacheKey"); 209 195 210 196 List<Link> otherLinks = new ArrayList<Link>(); … … 217 203 218 204 Content tagline = new Content(); 219 220 205 tagline.setValue(FEED_TAGLINE()); 221 206 setTagline(tagline); 207 222 208 setUpdated(new Date()); 223 209 setIcon(FEED_ICON()); … … 230 216 setAuthors(feedAuthors); 231 217 232 // Add each Article as a Feed Entry 218 String xmlBase = (cacheKey.getRelativeLinks() ? "" : JOURNAL_URI); 219 220 221 FEED_TYPES t = cacheKey.feedType(); 222 223 List<String> articleIds = (List<String>) ai.getStack().findValue("Ids"); 224 225 // Add each Article or Annotations as a Feed Entry 233 226 List<Entry> entries = null; 234 227 … … 237 230 case FormalCorrectionAnnot: 238 231 case MinorCorrectionAnnot: 232 case RetractionAnnot: 239 233 case CommentAnnot: 240 entries = buildAnnotationFeed(xmlBase); 234 List<WebAnnotation> annotations = feedService.getAnnotations(articleIds); 235 List<String> replyIds = (List<String>) ai.getStack().findValue("ReplyIds"); 236 List<WebReply> replies = feedService.getReplies(replyIds); 237 entries = buildAnnotationFeed(xmlBase, annotations, replies, cacheKey.getMaxResults()); 241 238 break; 242 239 case Article : 243 240 case Issue : 244 entries = buildArticleFeed(cacheKey, xmlBase); 241 List<Article> articles = feedService.getArticles(articleIds); 242 entries = buildArticleFeed(cacheKey, xmlBase, articles); 245 243 break; 246 244 } … … 255 253 * 256 254 * @param xmlBase xml base url 255 * @param annotations list of web annotations 256 * @param replies list of web replies 257 * @param maxResults maximum number of results to display 257 258 * @return List of entries for the feed 258 259 * @throws Exception Exception 259 260 */ 260 private List<Entry> buildAnnotationFeed(String xmlBase) throws Exception { 261 private List<Entry> buildAnnotationFeed(String xmlBase, 262 List<WebAnnotation> annotations, 263 List<WebReply> replies, 264 int maxResults) 265 throws Exception { 266 267 // Combine annotations and replies sorted by date 268 SortedMap<Date, BaseAnnotation> map = new TreeMap<Date, BaseAnnotation>(); 269 270 for (WebAnnotation annotation : annotations) { 271 map.put(annotation.getCreatedAsDate(), annotation); 272 } 273 274 for (WebReply reply : replies) { 275 map.put(reply.getCreatedAsDate(), reply); 276 } 277 261 278 // Add each Article as a Feed Entry 262 279 List<Entry> entries = new ArrayList<Entry>(); 263 280 264 for (WebAnnotation annot : annotations) { 281 int i = 0; 282 for (BaseAnnotation annot : map.values()) { 283 265 284 Entry entry = newEntry(annot); 266 List<String> ids = new ArrayList<String>(); 267 List<Article> art; 268 List<Link> altLinks = new ArrayList<Link>(); 269 270 ids.add(annot.getAnnotates()); 271 art = articleFeedService.getArticles(ids); 285 286 String displayName; 287 List<String> articleIds = new ArrayList<String>(); 288 if (annot instanceof WebReply) { 289 WebReply webReply = (WebReply) annot; 290 List<String> rootAnnotationIds = new ArrayList<String>(); 291 rootAnnotationIds.add(webReply.getRoot()); 292 List<WebAnnotation> rootAnnotations = feedService.getAnnotations(rootAnnotationIds); 293 articleIds.add(rootAnnotations.get(0).getAnnotates()); 294 displayName = "Reply"; 295 } else { 296 WebAnnotation webAnnotation = (WebAnnotation) annot; 297 articleIds.add(webAnnotation.getAnnotates()); 298 displayName = webAnnotation.getDisplayName(); 299 } 300 301 List<Article> art = feedService.getArticles(articleIds); 272 302 273 303 // Link to annotation via xmlbase 274 304 Link selfLink = newSelfLink(annot, xmlBase); 305 306 List<Link> altLinks = new ArrayList<Link>(); 275 307 altLinks.add(selfLink); 276 308 … … 287 319 Person person = new Person(); 288 320 289 UserAccount ua = articleFeedService.getUserAcctFrmID(annot.getCreator());321 UserAccount ua = feedService.getUserAcctFrmID(annot.getCreator()); 290 322 if (ua != null) 291 323 person.setName(ua.getProfile().getDisplayName()); … … 296 328 entry.setAuthors(authors); 297 329 298 List <Content> contents = newAnnotationsList( annot, selfLink);330 List <Content> contents = newAnnotationsList(selfLink, displayName, annot.getComment()); 299 331 entry.setContents(contents); 300 332 301 List<com.sun.syndication.feed.atom.Category> categories = newCategoryList( annot);333 List<com.sun.syndication.feed.atom.Category> categories = newCategoryList(displayName); 302 334 entry.setCategories(categories); 303 335 304 336 // Add completed Entry to List 305 337 entries.add(entry); 338 339 // i starts with 1, if maxResults=0 this will not interrupt the loop 340 if (++i == maxResults) 341 break; 306 342 } 307 343 return entries; … … 312 348 * by the query action. 313 349 * 314 * @param cacheKey cache/data model350 * @param cacheKey cache/data model 315 351 * @param xmlBase xml base url 352 * @param articles list of articles 316 353 * @return List of entries for feed. 317 354 */ 318 private List<Entry> buildArticleFeed( FeedCacheKey cacheKey, String xmlBase) {355 private List<Entry> buildArticleFeed(ArticleFeedCacheKey cacheKey, String xmlBase, List<Article> articles) { 319 356 // Add each Article as a Feed Entry 320 357 List<Entry> entries = new ArrayList<Entry>(); … … 456 493 * @return List<Content> consisting of HTML descriptions of the article and author 457 494 */ 458 private List<Content>newContentsList( FeedCacheKey cacheKey, Article article, String authorNames,495 private List<Content>newContentsList(ArticleFeedCacheKey cacheKey, Article article, String authorNames, 459 496 int numAuthors) { 460 497 List<Content> contents = new ArrayList<Content>(); … … 490 527 * the Author (or Authors if extended format) and the DublinCore description of the article. 491 528 * 492 * @param annotation annotation to convert into Content element493 529 * @param link link to the article 494 530 * 531 * @param entryTypeDisplay text to describe type of entry : FormalCorrection, Reply ... 532 * @param comment Comment 495 533 * @return List<Content> consisting of HTML descriptions of the article and author 496 534 * … … 498 536 */ 499 537 500 private List<Content>newAnnotationsList(WebAnnotation annotation, Link link) 501 throws ApplicationException { 538 private List<Content> newAnnotationsList(Link link, String entryTypeDisplay, String comment) 539 throws ApplicationException { 540 502 541 List<Content> contents = new ArrayList<Content>(); 503 542 Content description = new Content(); 504 String displayName = annotation.getDisplayName();505 543 description.setType("html"); 506 544 507 545 StringBuilder text = new StringBuilder(); 508 546 text.append("<p>"); 509 if ( displayName != null) {510 String d = displayName + " on ";511 text.append(d); 512 }513 514 {515 String d = " <a href=" + link.getHref() + ">" + link.getTitle() + "</a></p>";516 text.append(d);517 d = "<p>" + annotation.getComment() + "</p>";518 text.append(d);519 }547 if (entryTypeDisplay != null) 548 text.append(entryTypeDisplay).append(" on "); 549 550 text.append(" <a href=") 551 .append(link.getHref()) 552 .append('>') 553 .append(link.getTitle()) 554 .append("</a></p>") 555 .append("<p>") 556 .append(comment) 557 .append("</p>"); 520 558 description.setValue(text.toString()); 521 559 contents.add(description); … … 553 591 * @return String of authors names. 554 592 */ 555 private String newAuthorsList( FeedCacheKey cacheKey, Article article, List<Person> authors) {593 private String newAuthorsList(ArticleFeedCacheKey cacheKey, Article article, List<Person> authors) { 556 594 Citation bc = article.getDublinCore().getBibliographicCitation(); 557 595 StringBuilder authorNames = new StringBuilder(); … … 628 666 * @return link to the article 629 667 */ 630 private Link newSelfLink(WebAnnotation annot, String xmlBase) { 668 private Link newSelfLink(BaseAnnotation annot, String xmlBase) { 669 670 String url; 671 if (annot instanceof WebReply) { 672 url = ((WebReply)annot).getRoot(); 673 } else { 674 url = doiToUrl(annot.getId()); 675 } 676 677 StringBuilder href = new StringBuilder(xmlBase) 678 .append("annotation/listThread.action?inReplyTo=") 679 .append(url) 680 .append("&root=") 681 .append(url); 682 683 // add anchor 684 if (annot instanceof WebReply) { 685 href.append('#').append(annot.getId()); 686 } 687 631 688 Link link = new Link(); 632 String href = xmlBase + "annotation/listThread.action?inReplyTo=";633 String url = doiToUrl(annot.getId());634 635 689 link.setRel("alternate"); 636 link.setHref(href + url + "&root=" + url);690 link.setHref(href.toString()); 637 691 link.setTitle(annot.getCommentTitle()); 638 692 return link; … … 691 745 * @return Entry feed entry 692 746 */ 693 private Entry newEntry( WebAnnotation annot) {747 private Entry newEntry(BaseAnnotation annot) { 694 748 Entry entry = new Entry(); 695 749 … … 704 758 } 705 759 760 706 761 /** 707 762 * Create a default Plos person element. … … 728 783 * @return <code>Link</code> user provide link. 729 784 */ 730 private Link newLink( FeedCacheKey cacheKey, String uri) {785 private Link newLink(ArticleFeedCacheKey cacheKey, String uri) { 731 786 if (cacheKey.getSelfLink() == null || cacheKey.getSelfLink().equals("")) { 732 787 if (uri.startsWith("/")) { … … 748 803 * Build an atom feed categroy list for for the WebAnnotation. 749 804 * 750 * @param annotation build category element from annotation 751 * 805 * @param displayName Name of the entry. 752 806 * @return List of atom categories 753 807 */ 754 public List<com.sun.syndication.feed.atom.Category> newCategoryList( WebAnnotation annotation) {808 public List<com.sun.syndication.feed.atom.Category> newCategoryList(String displayName) { 755 809 List<com.sun.syndication.feed.atom.Category> categories = 756 810 new ArrayList<com.sun.syndication.feed.atom.Category>(); 757 811 com.sun.syndication.feed.atom.Category cat = new com.sun.syndication.feed.atom.Category(); 758 812 759 cat.setTerm( annotation.getDisplayName());760 cat.setLabel( annotation.getDisplayName());813 cat.setTerm(displayName); 814 cat.setLabel(displayName); 761 815 categories.add(cat); 762 816 … … 771 825 * @return String identifier generated for this feed 772 826 */ 773 private String newFeedID( FeedCacheKey cacheKey) {827 private String newFeedID(ArticleFeedCacheKey cacheKey) { 774 828 String id = FEED_ID(); 775 829 if (cacheKey.getCategory() != null && cacheKey.getCategory().length() > 0) … … 787 841 * @return String feed title. 788 842 */ 789 private String newFeedTitle( FeedCacheKey cacheKey) {843 private String newFeedTitle(ArticleFeedCacheKey cacheKey) { 790 844 String feedTitle = cacheKey.getTitle(); 791 845 … … 870 924 * @param articleXmlUtils a set of XML transformation utilities 871 925 */ 926 @Required 872 927 public void setArticleXmlUtils(ArticleXMLUtils articleXmlUtils) { 873 928 this.articleXmlUtils = articleXmlUtils; … … 875 930 876 931 /** 877 * @param articleFeedService Article Feed Service 878 */ 879 public void setArticleFeedService(ArticleFeedService articleFeedService) { 880 this.articleFeedService = articleFeedService; 932 * @param feedService Article Feed Service 933 */ 934 @Required 935 public void setFeedService(FeedService feedService) { 936 this.feedService = feedService; 881 937 } 882 938 } -
head/ambra/webapp/src/main/resources/struts.xml
r7569 r7613 427 427 <default-action-ref name="pageNotFound" /> 428 428 429 <action name="getFeed" class="org.topazproject.ambra.article.action.ArticleFeed"> 430 <result name="success" type="feed"> 431 <param name="feedName">wireFeed</param> 429 <action name="getFeed" class="org.topazproject.ambra.feed.action.FeedAction"> 430 <result name="success" type="feed"/> 431 <result name="input" type="httpheader"> 432 <param name="status">400</param><!-- Http status: Bad Request--> 432 433 </result> 433 434 </action> -
head/ambra/webapp/src/main/webapp/discussion/threaded_replies.ftl
r7601 r7613 2 2 $HeadURL:: $ 3 3 $Id$ 4 4 5 5 Copyright (c) 2007-2009 by Topaz, Inc. 6 6 http://topazproject.org 7 7 8 8 Licensed under the Apache License, Version 2.0 (the "License"); 9 9 you may not use this file except in compliance with the License. 10 10 You may obtain a copy of the License at 11 11 12 12 http://www.apache.org/licenses/LICENSE-2.0 13 13 14 14 Unless required by applicable law or agreed to in writing, software 15 15 distributed under the License is distributed on an "AS IS" BASIS, … … 31 31 <div class="hd"> 32 32 <!-- begin response title --> 33 <h3> ${reply.commentTitle}</h3>33 <h3><a name="${reply.id}">${reply.commentTitle}</a></h3> 34 34 <!-- end : response title --> 35 35 <!-- begin : response poster details --> … … 97 97 <div class="hd"> 98 98 <!-- begin response title --> 99 <h3> ${baseAnnotation.commentTitle}</h3>99 <h3><a name="${baseAnnotation.id}">${baseAnnotation.commentTitle}</a></h3> 100 100 <!-- end : response title --> 101 101 <!-- begin : response poster detail --> -
head/ambra/webapp/src/main/webapp/WEB-INF/applicationContext.xml
r7599 r7613 94 94 </bean> 95 95 96 <bean id=" articleFeedService" class="org.topazproject.ambra.article.service.ArticleFeedService">96 <bean id="feedService" class="org.topazproject.ambra.feed.service.FeedService"> 97 97 <property name="articleOtmService" ref="articleOtmService"/> 98 98 <property name="annotationService" ref="annotationService"/> -
head/ambra/webapp/src/test/java/org/topazproject/ambra/annotation/service/AnnotationServiceTest.java
r7331 r7613 54 54 import java.util.ArrayList; 55 55 import java.util.List; 56 import java.util.HashSet; 57 import java.util.Set; 56 58 import java.text.SimpleDateFormat; 57 59 import java.text.ParseException; … … 147 149 } 148 150 149 151 150 152 @Test 151 public void getAnnotation s() throws ParseException, URISyntaxException {153 public void getAnnotationIds() throws ParseException, URISyntaxException { 152 154 153 155 IMocksControl ctl = createControl(); … … 155 157 PDP pdp = ctl.createMock(PDP.class); 156 158 Session session = ctl.createMock(Session.class); 157 Query query = ctl.createMock(Query.class);158 Results results = ctl.createMock(Results.class);159 Query annQuery = ctl.createMock(Query.class); 160 Results annResults = ctl.createMock(Results.class); 159 161 CacheManager cacheManager = ctl.createMock(CacheManager.class); 160 162 MockCache cache = new MockCache(); … … 164 166 Date startDate = dateFormat.parse("02/01/2009"); 165 167 Date endDate = dateFormat.parse("03/10/2009"); 166 int[] states = {0, 1}; 167 List<String> annotType = new ArrayList<String>(); 168 Set<String> annotType = new HashSet<String>(); 168 169 annotType.add("FormalCorrection"); 169 170 annotType.add("MinorCorrection"); 170 171 171 String articleId = "info:doi/10.1371/journal.pone.0002250"; 172 String queryString = "select a.id id, cr from Annotation a " + 173 "where cr := a.created and a.annotates = :targ and a.mediator = :med and ge(cr, :sd) " + 174 "and le(cr, :ed) and (art.state = :st0 or art.state = :st1) " + 172 String queryString = "select a.id id, cr from ArticleAnnotation a, Article ar " + 173 "where a.annotates = ar " + 174 "and cr := a.created " + 175 "and ge(cr, :sd) " + 176 "and le(cr, :ed) " + 175 177 "and (a.<rdf:type> = :type0 or a.<rdf:type> = :type1) " + 176 "order by cr asc, id asc limit 20;"; 178 "order by cr asc, id asc limit 3;"; 179 177 180 String applicationId = "test-app"; 181 178 182 URI annotation1id = URI.create("info:doi/10.1371/annotation1"); 179 183 URI annotation2id = URI.create("info:doi/10.1371/annotation2"); 180 184 URI annotation3id = URI.create("info:doi/10.1371/annotation3"); 181 185 182 Comment comment = new Comment(); 183 comment.setId(annotation1id); 184 FormalCorrection formalCorrection = new FormalCorrection(); 185 formalCorrection.setId(annotation2id); 186 MinorCorrection minorCorrection = new MinorCorrection(); 187 minorCorrection.setId(annotation3id); 188 189 List<ArticleAnnotation> expected = new ArrayList<ArticleAnnotation>(); 190 expected.add(comment); 191 expected.add(formalCorrection); 192 expected.add(minorCorrection); 186 List<String> expected = new ArrayList<String>(); 187 expected.add(annotation1id.toString()); 188 expected.add(annotation2id.toString()); 189 expected.add(annotation3id.toString()); 193 190 194 191 cacheManager.registerListener(isA(AbstractObjectListener.class)); … … 199 196 .anyTimes(); 200 197 198 // Run Annotation Query 201 199 expect(session.createQuery(queryString)) 202 .andReturn(query); 203 expect(query.setParameter("targ", articleId)) 204 .andReturn(query); 205 expect(query.setParameter("med", applicationId)) 206 .andReturn(query); 207 expect(query.setParameter("sd", startDate)) 208 .andReturn(query); 209 expect(query.setParameter("ed", endDate)) 210 .andReturn(query); 211 212 for (int i = 0; i < states.length; i++) { 213 expect(query.setParameter("st"+i, states[i])) 214 .andReturn(query); 200 .andReturn(annQuery); 201 expect(annQuery.setParameter("sd", startDate)) 202 .andReturn(annQuery); 203 expect(annQuery.setParameter("ed", endDate)) 204 .andReturn(annQuery); 205 206 int i = 0; 207 for (String type : annotType) { 208 expect(annQuery.setUri("type"+i++, URI.create(type))) 209 .andReturn(annQuery); 215 210 } 216 211 217 for (int i = 0; i < annotType.size(); i++) { 218 expect(query.setUri("type"+i, URI.create(annotType.get(i)))) 219 .andReturn(query); 220 } 221 222 expect(query.execute()) 223 .andReturn(results); 224 225 expect(results.next()) 212 expect(annQuery.execute()) 213 .andReturn(annResults); 214 215 expect(annResults.next()) 226 216 .andReturn(true).times(3) 227 217 .andReturn(false); 228 expect( results.getURI(0))218 expect(annResults.getURI(0)) 229 219 .andReturn(annotation1id) 230 220 .andReturn(annotation2id) 231 221 .andReturn(annotation3id); 232 233 expect(session.get(ArticleAnnotation.class, annotation1id.toString())) 234 .andReturn(comment); 235 expect(session.get(ArticleAnnotation.class, annotation2id.toString())) 236 .andReturn(formalCorrection); 237 expect(session.get(ArticleAnnotation.class, annotation3id.toString())) 238 .andReturn(minorCorrection); 239 222 240 223 ctl.replay(); 241 224 … … 251 234 252 235 253 List< ArticleAnnotation> annotations = annotationService.getAnnotations(254 articleId, startDate, endDate, applicationId, annotType, states, true, 20);255 256 assertEquals(annotation s, expected);236 List<String> annotationIds = annotationService.getAnnotationIds(startDate, endDate, 237 new HashSet<String>(annotType), 3); 238 239 assertEquals(annotationIds, expected); 257 240 258 241 ctl.verify();
