diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/query-calendar-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/query-calendar-common-SqlMap.xml
index 3b9f8c1873..9dee99e38e 100644
--- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/query-calendar-common-SqlMap.xml
+++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/query-calendar-common-SqlMap.xml
@@ -12,7 +12,9 @@
-
+
+
+
@@ -28,6 +30,8 @@
childNode.audit_creator as audit_creator,
prop_fromdate.string_value as from_date,
prop_todate.string_value as to_date,
+ prop_recurrenceRule.string_value as recurrence_rule,
+ prop_recurrenceLastMeeting.string_value as recurrence_last_meeting,
prop_name.string_value as name
from
alf_child_assoc assoc
@@ -35,6 +39,8 @@
join alf_store childStore on (childStore.id = childNode.store_id)
left join alf_node_properties prop_fromdate on (prop_fromdate.node_id = childNode.id and prop_fromdate.qname_id = #{fromDateQNameId})
left join alf_node_properties prop_todate on (prop_todate.node_id = childNode.id and prop_todate.qname_id = #{toDateQNameId})
+ left join alf_node_properties prop_recurrenceRule on (prop_recurrenceRule.node_id = childNode.id and prop_recurrenceRule.qname_id = #{recurrenceRuleQNameId})
+ left join alf_node_properties prop_recurrenceLastMeeting on (prop_recurrenceLastMeeting.node_id = childNode.id and prop_recurrenceLastMeeting.qname_id = #{recurrenceLastMeetingQNameId})
left join alf_node_properties prop_name on (prop_name.node_id = childNode.id and prop_name.qname_id = #{nameQNameId})
where
assoc.parent_node_id IN #{nodeRef}
diff --git a/source/java/org/alfresco/repo/calendar/CalendarHelpersTest.java b/source/java/org/alfresco/repo/calendar/CalendarHelpersTest.java
index 130c11d056..89efdd02ea 100644
--- a/source/java/org/alfresco/repo/calendar/CalendarHelpersTest.java
+++ b/source/java/org/alfresco/repo/calendar/CalendarHelpersTest.java
@@ -20,9 +20,7 @@ package org.alfresco.repo.calendar;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -32,35 +30,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.alfresco.model.ContentModel;
-import org.alfresco.query.PagingRequest;
-import org.alfresco.query.PagingResults;
-import org.alfresco.repo.policy.BehaviourFilter;
-import org.alfresco.repo.security.authentication.AuthenticationUtil;
-import org.alfresco.repo.site.SiteModel;
-import org.alfresco.repo.transaction.RetryingTransactionHelper;
-import org.alfresco.service.cmr.calendar.CalendarEntry;
import org.alfresco.service.cmr.calendar.CalendarEntryDTO;
import org.alfresco.service.cmr.calendar.CalendarRecurrenceHelper;
import org.alfresco.service.cmr.calendar.CalendarService;
-import org.alfresco.service.cmr.dictionary.DictionaryService;
-import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
-import org.alfresco.service.cmr.security.MutableAuthenticationService;
-import org.alfresco.service.cmr.security.PermissionService;
-import org.alfresco.service.cmr.security.PersonService;
-import org.alfresco.service.cmr.site.SiteInfo;
-import org.alfresco.service.cmr.site.SiteService;
-import org.alfresco.service.cmr.site.SiteVisibility;
-import org.alfresco.service.cmr.tagging.TaggingService;
-import org.alfresco.util.ApplicationContextHelper;
-import org.alfresco.util.PropertyMap;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.ApplicationContext;
/**
* Test cases for the helpers relating to the {@link CalendarService},
@@ -624,6 +597,13 @@ public class CalendarHelpersTest
CalendarRecurrenceHelper.buildMonthlyRecurrences(
currentDate, dates, params, onOrAfter, until, firstOnly, interval);
}
+
+ protected static void buildYearlyRecurrences(Calendar currentDate, List dates,
+ Map params, Date onOrAfter, Date until, boolean firstOnly, int interval)
+ {
+ CalendarRecurrenceHelper.buildYearlyRecurrences(
+ currentDate, dates, params, onOrAfter, until, firstOnly, interval);
+ }
}
private static Date date(int year, int month, int day)
diff --git a/source/java/org/alfresco/repo/calendar/CalendarServiceImpl.java b/source/java/org/alfresco/repo/calendar/CalendarServiceImpl.java
index 15a95bdba0..21203867d9 100644
--- a/source/java/org/alfresco/repo/calendar/CalendarServiceImpl.java
+++ b/source/java/org/alfresco/repo/calendar/CalendarServiceImpl.java
@@ -69,8 +69,8 @@ public class CalendarServiceImpl implements CalendarService
*/
private static final int MAX_QUERY_ENTRY_COUNT = 10000;
- private static final String CANNED_QUERY_GET_CHILDREN = "calendarGetChildrenCannedQueryFactory";
- private static final String CANNED_QUERY_GET_ENTRIES = "calendarGetCalendarEntriesCannedQueryFactory";
+ protected static final String CANNED_QUERY_GET_CHILDREN = "calendarGetChildrenCannedQueryFactory";
+ protected static final String CANNED_QUERY_GET_ENTRIES = "calendarGetCalendarEntriesCannedQueryFactory";
/**
* The logger
@@ -262,7 +262,6 @@ public class CalendarServiceImpl implements CalendarService
}
// Make the changes
- taggingService.clearTags(nodeRef);
for(String tag : toDel)
{
taggingService.removeTag(nodeRef, tag);
@@ -346,20 +345,31 @@ public class CalendarServiceImpl implements CalendarService
@Override
public CalendarEntry updateCalendarEntry(CalendarEntry entry) {
- Map properties = CalendarEntryImpl.toNodeProperties(entry);
-
+ // Sanity check what we were given
if(entry.getNodeRef() == null)
{
throw new IllegalArgumentException("Can't update a calendar entry that was never persisted, call create instead");
}
- // Update the existing one
+ // Get the Calendar properties
+ Map properties = CalendarEntryImpl.toNodeProperties(entry);
+
+ // Merge in the non calendar ones
+ for(Map.Entry prop : nodeService.getProperties(entry.getNodeRef()).entrySet())
+ {
+ if(! prop.getKey().getNamespaceURI().equals(CalendarModel.CALENDAR_MODEL_URL))
+ {
+ properties.put(prop.getKey(), prop.getValue());
+ }
+ }
+
+ // Save the new properties
nodeService.setProperties(entry.getNodeRef(), properties);
- // Update tags
+ // Update the tags
handleTags(entry);
- // Nothing changed
+ // Nothing was changed on the entry itself
return entry;
}
diff --git a/source/java/org/alfresco/repo/calendar/CalendarServiceImplTest.java b/source/java/org/alfresco/repo/calendar/CalendarServiceImplTest.java
index a0981fe4a7..86abb93d5a 100644
--- a/source/java/org/alfresco/repo/calendar/CalendarServiceImplTest.java
+++ b/source/java/org/alfresco/repo/calendar/CalendarServiceImplTest.java
@@ -30,8 +30,14 @@ import java.util.Date;
import java.util.List;
import org.alfresco.model.ContentModel;
+import org.alfresco.query.CannedQueryFactory;
+import org.alfresco.query.CannedQueryResults;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
+import org.alfresco.repo.calendar.cannedqueries.CalendarEntity;
+import org.alfresco.repo.calendar.cannedqueries.GetCalendarEntriesCannedQuery;
+import org.alfresco.repo.calendar.cannedqueries.GetCalendarEntriesCannedQueryFactory;
+import org.alfresco.repo.calendar.cannedqueries.GetCalendarEntriesCannedQueryTestHook;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.site.SiteModel;
@@ -50,7 +56,9 @@ import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.cmr.site.SiteVisibility;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.util.ApplicationContextHelper;
+import org.alfresco.util.ISO8601DateFormat;
import org.alfresco.util.PropertyMap;
+import org.alfresco.util.registry.NamedObjectRegistry;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@@ -82,6 +90,7 @@ public class CalendarServiceImplTest
private static PermissionService PERMISSION_SERVICE;
private static SiteService SITE_SERVICE;
private static TaggingService TAGGING_SERVICE;
+ private static GetCalendarEntriesCannedQueryFactory CALENDAR_CQ_FACTORY;
private static final String TEST_USER = CalendarServiceImplTest.class.getSimpleName() + "_testuser";
private static final String ADMIN_USER = AuthenticationUtil.getAdminUserName();
@@ -111,7 +120,14 @@ public class CalendarServiceImplTest
PERMISSION_SERVICE = (PermissionService)testContext.getBean("permissionService");
SITE_SERVICE = (SiteService)testContext.getBean("siteService");
TAGGING_SERVICE = (TaggingService)testContext.getBean("TaggingService");
+
+ // Get the canned query registry, and from that the factory
+ NamedObjectRegistry> calendarCannedQueryRegistry =
+ (NamedObjectRegistry>)testContext.getBean("calendarCannedQueryRegistry");
+ CALENDAR_CQ_FACTORY = (GetCalendarEntriesCannedQueryFactory)
+ calendarCannedQueryRegistry.getNamedObject(CalendarServiceImpl.CANNED_QUERY_GET_ENTRIES);
+ // Do the setup as admin
AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER);
createUser(TEST_USER);
@@ -335,6 +351,7 @@ public class CalendarServiceImplTest
"Title", "Description", "Location", new Date(1), new Date(1234)
);
entry = CALENDAR_SERVICE.createCalendarEntry(CALENDAR_SITE.getShortName(), entry);
+ testNodesToTidy.add(entry.getNodeRef());
// Check
assertEquals(0, entry.getTags().size());
@@ -364,9 +381,15 @@ public class CalendarServiceImplTest
entry.getTags().add(TAG_1);
CALENDAR_SERVICE.updateCalendarEntry(entry);
- // Check
- entry = CALENDAR_SERVICE.getCalendarEntry(CALENDAR_SITE.getShortName(), entry.getSystemName());
- assertEquals(2, entry.getTags().size());
+ // Check it as-is
+ assertEquals(3, entry.getTags().size()); // Includes duplicate tag until re-loaded
+ assertEquals(true, entry.getTags().contains(TAG_1));
+ assertEquals(false, entry.getTags().contains(TAG_2));
+ assertEquals(true, entry.getTags().contains(TAG_3));
+
+ // Now load and re-check
+ entry = CALENDAR_SERVICE.getCalendarEntry(CALENDAR_SITE.getShortName(), entry.getSystemName());
+ assertEquals(2, entry.getTags().size()); // Duplicate now gone
assertEquals(true, entry.getTags().contains(TAG_1));
assertEquals(false, entry.getTags().contains(TAG_2));
assertEquals(true, entry.getTags().contains(TAG_3));
@@ -632,15 +655,18 @@ public class CalendarServiceImplTest
// Now add some events to one site
- CALENDAR_SERVICE.createCalendarEntry(CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
+ NodeRef c1 = CALENDAR_SERVICE.createCalendarEntry(CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
"TitleA", "Description", "Location", new Date(1302431400), new Date(1302442200)
- ));
- CALENDAR_SERVICE.createCalendarEntry(CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
+ )).getNodeRef();
+ NodeRef c2 = CALENDAR_SERVICE.createCalendarEntry(CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
"TitleB", "Description", "Location", new Date(1302435000), new Date(1302435000)
- ));
- CALENDAR_SERVICE.createCalendarEntry(CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
+ )).getNodeRef();
+ NodeRef c3 = CALENDAR_SERVICE.createCalendarEntry(CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
"TitleC", "Description", "Location", new Date(1302431400), new Date(1302435000)
- ));
+ )).getNodeRef();
+ testNodesToTidy.add(c1);
+ testNodesToTidy.add(c2);
+ testNodesToTidy.add(c3);
// Check
@@ -649,20 +675,30 @@ public class CalendarServiceImplTest
assertEquals(3, results.getPage().size());
// Should be date ordered, from then too
- assertEquals("TitleA", results.getPage().get(0).getTitle());
- assertEquals("TitleC", results.getPage().get(1).getTitle());
+ assertEquals("TitleC", results.getPage().get(0).getTitle()); // Same start as A, earlier end
+ assertEquals("TitleA", results.getPage().get(1).getTitle());
assertEquals("TitleB", results.getPage().get(2).getTitle());
// Add some to the other site, which the user isn't a member of
AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER);
- CALENDAR_SERVICE.createCalendarEntry(ALTERNATE_CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
+ NodeRef ca1 = CALENDAR_SERVICE.createCalendarEntry(ALTERNATE_CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
"PrivateTitleA", "Description", "Location", new Date(1302131400), new Date(1302135000)
- ));
- CALENDAR_SERVICE.createCalendarEntry(ALTERNATE_CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
+ )).getNodeRef();
+ NodeRef ca2 = CALENDAR_SERVICE.createCalendarEntry(ALTERNATE_CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
"PrivateTitleB", "Description", "Location", new Date(1302731400), new Date(1302472200)
- ));
+ )).getNodeRef();
AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER);
+ testNodesToTidy.add(ca1);
+ testNodesToTidy.add(ca2);
+
+ // Our nodes are now, in start+end order:
+ // PrivateTitleA 1302131400 -> 1302135000
+ // TitleC 1302431400 -> 1302435000
+ // TitleA 1302431400 -> 1302442200
+ // TitleB 1302435000 -> 1302435000
+ // PrivateTitleB 1302731400 -> 1302472200
+
// Check, they won't show up due to permissions
results = CALENDAR_SERVICE.listCalendarEntries(new String[] {
@@ -690,8 +726,8 @@ public class CalendarServiceImplTest
// Should be date ordered, from then too
assertEquals("PrivateTitleA", results.getPage().get(0).getTitle());
- assertEquals("TitleA", results.getPage().get(1).getTitle());
- assertEquals("TitleC", results.getPage().get(2).getTitle());
+ assertEquals("TitleC", results.getPage().get(1).getTitle());
+ assertEquals("TitleA", results.getPage().get(2).getTitle());
assertEquals("TitleB", results.getPage().get(3).getTitle());
assertEquals("PrivateTitleB", results.getPage().get(4).getTitle());
@@ -704,12 +740,22 @@ public class CalendarServiceImplTest
new Date(1300031400), null, paging);
assertEquals(5, results.getPage().size());
- // Date in the middle
+ // Date in the middle, several just finishing
results = CALENDAR_SERVICE.listCalendarEntries(new String[] {
CALENDAR_SITE.getShortName(), ALTERNATE_CALENDAR_SITE.getShortName()},
new Date(1302435000), null, paging);
+ assertEquals(4, results.getPage().size());
+ assertEquals("TitleC", results.getPage().get(0).getTitle());
+ assertEquals("TitleA", results.getPage().get(1).getTitle());
+ assertEquals("TitleB", results.getPage().get(2).getTitle());
+ assertEquals("PrivateTitleB", results.getPage().get(3).getTitle());
+
+ // Date in the middle, past the finish of many
+ results = CALENDAR_SERVICE.listCalendarEntries(new String[] {
+ CALENDAR_SITE.getShortName(), ALTERNATE_CALENDAR_SITE.getShortName()},
+ new Date(1302441000), null, paging);
assertEquals(2, results.getPage().size());
- assertEquals("TitleB", results.getPage().get(0).getTitle());
+ assertEquals("TitleA", results.getPage().get(0).getTitle());
assertEquals("PrivateTitleB", results.getPage().get(1).getTitle());
// Date in the future
@@ -727,16 +773,25 @@ public class CalendarServiceImplTest
null, new Date(1300031400), paging);
assertEquals(0, results.getPage().size());
- // Date in the middle
+ // Date in the middle, with some touching on the end date
results = CALENDAR_SERVICE.listCalendarEntries(new String[] {
CALENDAR_SITE.getShortName(), ALTERNATE_CALENDAR_SITE.getShortName()},
null, new Date(1302435000), paging);
assertEquals(4, results.getPage().size());
assertEquals("PrivateTitleA", results.getPage().get(0).getTitle());
- assertEquals("TitleA", results.getPage().get(1).getTitle());
- assertEquals("TitleC", results.getPage().get(2).getTitle());
+ assertEquals("TitleC", results.getPage().get(1).getTitle());
+ assertEquals("TitleA", results.getPage().get(2).getTitle());
assertEquals("TitleB", results.getPage().get(3).getTitle());
+ // Date in the middle, before the start date of several
+ results = CALENDAR_SERVICE.listCalendarEntries(new String[] {
+ CALENDAR_SITE.getShortName(), ALTERNATE_CALENDAR_SITE.getShortName()},
+ null, new Date(1302432400), paging);
+ assertEquals(3, results.getPage().size());
+ assertEquals("PrivateTitleA", results.getPage().get(0).getTitle());
+ assertEquals("TitleC", results.getPage().get(1).getTitle());
+ assertEquals("TitleA", results.getPage().get(2).getTitle());
+
// Date in the future
results = CALENDAR_SERVICE.listCalendarEntries(new String[] {
CALENDAR_SITE.getShortName(), ALTERNATE_CALENDAR_SITE.getShortName()},
@@ -749,16 +804,16 @@ public class CalendarServiceImplTest
CALENDAR_SITE.getShortName(), ALTERNATE_CALENDAR_SITE.getShortName()},
new Date(1302431400), new Date(1302432000), paging);
assertEquals(2, results.getPage().size());
- assertEquals("TitleA", results.getPage().get(0).getTitle());
- assertEquals("TitleC", results.getPage().get(1).getTitle());
+ assertEquals("TitleC", results.getPage().get(0).getTitle());
+ assertEquals("TitleA", results.getPage().get(1).getTitle());
results = CALENDAR_SERVICE.listCalendarEntries(new String[] {
CALENDAR_SITE.getShortName(), ALTERNATE_CALENDAR_SITE.getShortName()},
new Date(1302131400), new Date(1302432000), paging);
assertEquals(3, results.getPage().size());
assertEquals("PrivateTitleA", results.getPage().get(0).getTitle());
- assertEquals("TitleA", results.getPage().get(1).getTitle());
- assertEquals("TitleC", results.getPage().get(2).getTitle());
+ assertEquals("TitleC", results.getPage().get(1).getTitle());
+ assertEquals("TitleA", results.getPage().get(2).getTitle());
// Filter on just one site, won't see from the other
@@ -766,30 +821,150 @@ public class CalendarServiceImplTest
CALENDAR_SITE.getShortName()},
new Date(1302131400), new Date(1302432000), paging);
assertEquals(2, results.getPage().size());
- assertEquals("TitleA", results.getPage().get(0).getTitle());
- assertEquals("TitleC", results.getPage().get(1).getTitle());
+ assertEquals("TitleC", results.getPage().get(0).getTitle());
+ assertEquals("TitleA", results.getPage().get(1).getTitle());
results = CALENDAR_SERVICE.listCalendarEntries(new String[] {
ALTERNATE_CALENDAR_SITE.getShortName()},
new Date(1302131400), new Date(1302432000), paging);
assertEquals(1, results.getPage().size());
assertEquals("PrivateTitleA", results.getPage().get(0).getTitle());
-
-
- // Tidy
- paging = new PagingRequest(10);
- results = CALENDAR_SERVICE.listCalendarEntries(CALENDAR_SITE.getShortName(), paging);
- for(CalendarEntry entry : results.getPage())
- {
- testNodesToTidy.add(entry.getNodeRef());
- }
- results = CALENDAR_SERVICE.listCalendarEntries(ALTERNATE_CALENDAR_SITE.getShortName(), paging);
- for(CalendarEntry entry : results.getPage())
- {
- testNodesToTidy.add(entry.getNodeRef());
- }
}
+
+ /**
+ * Ensure that the canned query returns the right entity objects
+ * for the underlying calendar entries.
+ * Checks both the low level filtering, and the DB fetching of the
+ * properties used in the filter
+ */
+ @Test public void testCannedQueryEntityResults() throws Exception
+ {
+ PagingRequest paging = new PagingRequest(10);
+ NodeRef[] containers = new NodeRef[] {
+ SITE_SERVICE.getContainer(CALENDAR_SITE.getShortName(), CalendarServiceImpl.CALENDAR_COMPONENT),
+ SITE_SERVICE.getContainer(ALTERNATE_CALENDAR_SITE.getShortName(), CalendarServiceImpl.CALENDAR_COMPONENT),
+ };
+ Date from = new Date(1302431400);
+ Date to = new Date(1302442200);
+
+
+ // To capture the low level results
+ final List full = new ArrayList();
+ final List filtered = new ArrayList();
+ GetCalendarEntriesCannedQueryTestHook hook = new GetCalendarEntriesCannedQueryTestHook()
+ {
+ @Override
+ public void notifyComplete(List fullList,
+ List filteredList) {
+ full.clear();
+ filtered.clear();
+ full.addAll(fullList);
+ filtered.addAll(filteredList);
+ }
+ };
+
+
+ // With no entries, won't find anything
+ GetCalendarEntriesCannedQuery cq = (GetCalendarEntriesCannedQuery)CALENDAR_CQ_FACTORY.getCannedQuery(
+ containers, from, to, paging
+ );
+ cq.setTestHook(hook);
+ cq.execute();
+
+ assertEquals(0, full.size());
+ assertEquals(0, filtered.size());
+
+
+ // Add some events, with a mixture of repeating and non
+ CalendarEntry c1 = CALENDAR_SERVICE.createCalendarEntry(CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
+ "SiteNormal", "Description", "Location", new Date(1302431400), new Date(1302442200)
+ ));
+ CalendarEntry c2 = CALENDAR_SERVICE.createCalendarEntry(CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
+ "SiteRepeating", "Description", "Location", new Date(1302435000), new Date(1302435000)
+ ));
+ CalendarEntry c3 = CALENDAR_SERVICE.createCalendarEntry(ALTERNATE_CALENDAR_SITE.getShortName(), new CalendarEntryDTO(
+ "AltSiteNormal", "Description", "Location", new Date(1302431400), new Date(1302435000)
+ ));
+
+
+ // Do a fetch that'll include all of them
+ cq = (GetCalendarEntriesCannedQuery)CALENDAR_CQ_FACTORY.getCannedQuery(
+ containers, from, to, paging
+ );
+ cq.setTestHook(hook);
+ cq.execute();
+
+ assertEquals(3, full.size());
+ assertEquals(3, filtered.size());
+
+ // Check they have the right details on them, and are correctly sorted
+ assertEquals(c3.getSystemName(), filtered.get(0).getName());
+ assertEquals(ISO8601DateFormat.format(c3.getStart()), filtered.get(0).getFromDate());
+ assertEquals(ISO8601DateFormat.format(c3.getEnd()), filtered.get(0).getToDate());
+ assertEquals(c3.getRecurrenceRule(), filtered.get(0).getRecurrenceRule());
+ assertEquals(null, filtered.get(0).getRecurrenceLastMeeting());
+
+ assertEquals(c1.getSystemName(), filtered.get(1).getName());
+ assertEquals(ISO8601DateFormat.format(c1.getStart()), filtered.get(1).getFromDate());
+ assertEquals(ISO8601DateFormat.format(c1.getEnd()), filtered.get(1).getToDate());
+ assertEquals(c1.getRecurrenceRule(), filtered.get(1).getRecurrenceRule());
+ assertEquals(null, filtered.get(1).getRecurrenceLastMeeting());
+
+ assertEquals(c2.getSystemName(), filtered.get(2).getName());
+ assertEquals(ISO8601DateFormat.format(c2.getStart()), filtered.get(2).getFromDate());
+ assertEquals(ISO8601DateFormat.format(c2.getEnd()), filtered.get(2).getToDate());
+ assertEquals(c2.getRecurrenceRule(), filtered.get(2).getRecurrenceRule());
+ assertEquals(null, filtered.get(2).getRecurrenceLastMeeting());
+
+
+ // Now do one that'll only have some
+ from = new Date(1302431400-10);
+ to = new Date(1302431400+10);
+ cq = (GetCalendarEntriesCannedQuery)CALENDAR_CQ_FACTORY.getCannedQuery(
+ containers, from, to, paging
+ );
+ cq.setTestHook(hook);
+ cq.execute();
+
+ assertEquals(3, full.size());
+ assertEquals(2, filtered.size());
+
+ // Check the ordering and filtering
+ assertEquals(c3.getSystemName(), filtered.get(0).getName());
+ assertEquals(c1.getSystemName(), filtered.get(1).getName());
+
+
+ // Now make one repeating and check the correct info comes through
+ c3.setRecurrenceRule("FREQ=WEEKLY");
+ c3.setLastRecurrence(new Date(1303431400));
+ CALENDAR_SERVICE.updateCalendarEntry(c3);
+
+ cq = (GetCalendarEntriesCannedQuery)CALENDAR_CQ_FACTORY.getCannedQuery(
+ containers, from, to, paging
+ );
+ cq.setTestHook(hook);
+ cq.execute();
+ assertEquals(3, full.size());
+ assertEquals(2, filtered.size());
+
+ // Check the details
+ assertEquals(c3.getSystemName(), filtered.get(0).getName());
+ assertEquals(ISO8601DateFormat.format(c3.getStart()), filtered.get(0).getFromDate());
+ assertEquals(ISO8601DateFormat.format(c3.getEnd()), filtered.get(0).getToDate());
+ assertEquals(ISO8601DateFormat.format(c3.getLastRecurrence()), filtered.get(0).getRecurrenceLastMeeting());
+ assertEquals(c3.getRecurrenceRule(), filtered.get(0).getRecurrenceRule());
+
+ assertEquals(c1.getSystemName(), filtered.get(1).getName());
+ assertEquals(ISO8601DateFormat.format(c1.getStart()), filtered.get(1).getFromDate());
+ assertEquals(ISO8601DateFormat.format(c1.getEnd()), filtered.get(1).getToDate());
+ assertEquals(c1.getRecurrenceRule(), filtered.get(1).getRecurrenceRule());
+ assertEquals(null, filtered.get(1).getRecurrenceLastMeeting());
+ }
+
+
+ // --------------------------------------------------------------------------------
+
private static void createTestSites() throws Exception
{
final CalendarServiceImpl privateCalendarService = (CalendarServiceImpl)testContext.getBean("calendarService");
diff --git a/source/java/org/alfresco/repo/calendar/cannedqueries/CalendarEntity.java b/source/java/org/alfresco/repo/calendar/cannedqueries/CalendarEntity.java
index a64c06a29f..e98fd3bc2b 100644
--- a/source/java/org/alfresco/repo/calendar/cannedqueries/CalendarEntity.java
+++ b/source/java/org/alfresco/repo/calendar/cannedqueries/CalendarEntity.java
@@ -39,6 +39,8 @@ public class CalendarEntity
private String fromDate;
private String toDate;
+ private String recurrenceRule;
+ private String recurrenceLastMeeting;
// Supplemental query-related parameters
private Long parentNodeId;
@@ -46,6 +48,8 @@ public class CalendarEntity
private Long contentTypeQNameId;
private Long fromDateQNameId;
private Long toDateQNameId;
+ private Long recurrenceRuleQNameId;
+ private Long recurrenceLastMeetingQNameId;
/**
* Default constructor
@@ -55,13 +59,16 @@ public class CalendarEntity
}
public CalendarEntity(Long parentNodeId, Long nameQNameId, Long contentTypeQNameId,
- Long fromDateQNameId, Long toDateQNameId)
+ Long fromDateQNameId, Long toDateQNameId,
+ Long recurrenceRuleQNameId, Long recurrenceLastMeetingQNameId)
{
this.parentNodeId = parentNodeId;
this.nameQNameId = nameQNameId;
this.contentTypeQNameId = contentTypeQNameId;
this.fromDateQNameId = fromDateQNameId;
this.toDateQNameId = toDateQNameId;
+ this.recurrenceRuleQNameId = recurrenceRuleQNameId;
+ this.recurrenceLastMeetingQNameId = recurrenceLastMeetingQNameId;
}
public Long getId()
@@ -134,6 +141,33 @@ public class CalendarEntity
this.toDate = toISO8061;
}
+ /**
+ * SharePoint/Oulook rules string
+ */
+ public String getRecurrenceRule()
+ {
+ return recurrenceRule;
+ }
+
+ /**
+ * SharePoint/Oulook rules string
+ */
+ public void setRecurrenceRule(String recurrenceRule)
+ {
+ this.recurrenceRule = recurrenceRule;
+ }
+
+ // (ISO-8061)
+ public String getRecurrenceLastMeeting()
+ {
+ return recurrenceLastMeeting;
+ }
+
+ public void setRecurrenceLastMeeting(String recurrenceLastMeetingISO8601)
+ {
+ this.recurrenceLastMeeting = recurrenceLastMeetingISO8601;
+ }
+
// Supplemental query-related parameters
@@ -161,4 +195,14 @@ public class CalendarEntity
{
return toDateQNameId;
}
+
+ public Long getRecurrenceRuleQNameId()
+ {
+ return recurrenceRuleQNameId;
+ }
+
+ public Long getRecurrenceLastMeetingQNameId()
+ {
+ return recurrenceLastMeetingQNameId;
+ }
}
diff --git a/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQuery.java b/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQuery.java
index 1017106088..e08ae30769 100644
--- a/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQuery.java
+++ b/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQuery.java
@@ -33,6 +33,7 @@ import org.alfresco.repo.domain.query.CannedQueryDAO;
import org.alfresco.repo.security.permissions.impl.acegi.AbstractCannedQueryPermissions;
import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityBean;
import org.alfresco.service.cmr.calendar.CalendarEntry;
+import org.alfresco.service.cmr.calendar.CalendarRecurrenceHelper;
import org.alfresco.service.cmr.calendar.CalendarService;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
@@ -59,6 +60,7 @@ public class GetCalendarEntriesCannedQuery extends AbstractCannedQueryPermission
private final CannedQueryDAO cannedQueryDAO;
private final TaggingService taggingService;
private final NodeService nodeService;
+ private GetCalendarEntriesCannedQueryTestHook testHook;
public GetCalendarEntriesCannedQuery(
CannedQueryDAO cannedQueryDAO,
@@ -101,6 +103,9 @@ public class GetCalendarEntriesCannedQuery extends AbstractCannedQueryPermission
toDate = fromDate;
}
+ String recurringRule = result.getRecurrenceRule();
+ Date recurringLastDate = DefaultTypeConverter.INSTANCE.convert(Date.class, result.getRecurrenceLastMeeting());
+
// Only return entries in the right period
if(entriesFromDate != null)
{
@@ -112,13 +117,72 @@ public class GetCalendarEntriesCannedQuery extends AbstractCannedQueryPermission
}
if(entriesToDate != null)
{
- // Needs to start on or after the Filter End date
+ // Needs have started by the Filter To date
if(fromDate == null || fromDate.after(entriesToDate))
{
nextNodeIsAcceptable = false;
}
}
+ // Handle recurring events specially
+ if(recurringRule != null && !nextNodeIsAcceptable)
+ {
+ if(entriesToDate != null || recurringLastDate != null)
+ {
+ Date searchFrom = entriesFromDate;
+ if(searchFrom == null)
+ {
+ searchFrom = fromDate;
+ }
+ Date searchTo = entriesToDate;
+ if(searchTo == null)
+ {
+ searchTo = recurringLastDate;
+ }
+
+ List dates = CalendarRecurrenceHelper.getRecurrencesOnOrAfter(
+ recurringRule, fromDate, toDate, recurringLastDate,
+ searchFrom, searchTo, false
+ );
+ if(dates != null && dates.size() > 0)
+ {
+ // Do any of these fit?
+ for(Date date : dates)
+ {
+ if(entriesFromDate != null && entriesToDate != null)
+ {
+ // From and To date given, needs to sit between them
+ if(entriesFromDate.getTime() <= date.getTime() &&
+ date.getTime() <= entriesToDate.getTime())
+ {
+ nextNodeIsAcceptable = true;
+ break;
+ }
+ }
+ else if(entriesFromDate != null)
+ {
+ // From date but no end date, needs to be after the from
+ if(entriesFromDate.getTime() <= date.getTime())
+ {
+ nextNodeIsAcceptable = true;
+ break;
+ }
+ }
+ else if(entriesToDate != null)
+ {
+ // End date but no start date, needs to be before the from
+ if(date.getTime() <= entriesToDate.getTime())
+ {
+ nextNodeIsAcceptable = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Did it make the cut
if (nextNodeIsAcceptable)
{
filtered.add(result);
@@ -155,6 +219,11 @@ public class GetCalendarEntriesCannedQuery extends AbstractCannedQueryPermission
logger.debug("Base query: "+calendarEntries.size()+" in "+(System.currentTimeMillis()-start)+" msecs");
}
+ if(testHook != null)
+ {
+ testHook.notifyComplete(results, filtered);
+ }
+
return calendarEntries;
}
@@ -165,6 +234,11 @@ public class GetCalendarEntriesCannedQuery extends AbstractCannedQueryPermission
return false;
}
+ public void setTestHook(GetCalendarEntriesCannedQueryTestHook hook)
+ {
+ this.testHook = hook;
+ }
+
private class CalendarEntryImpl extends org.alfresco.repo.calendar.CalendarEntryImpl
{
private CalendarEntryImpl(CalendarEntity entity)
diff --git a/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQueryFactory.java b/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQueryFactory.java
index 3e3955473b..9907671c89 100644
--- a/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQueryFactory.java
+++ b/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQueryFactory.java
@@ -151,6 +151,8 @@ public class GetCalendarEntriesCannedQueryFactory extends AbstractCannedQueryFac
getQNameId(CalendarModel.TYPE_EVENT),
getQNameId(CalendarModel.PROP_FROM_DATE),
getQNameId(CalendarModel.PROP_TO_DATE),
+ getQNameId(CalendarModel.PROP_RECURRENCE_RULE),
+ getQNameId(CalendarModel.PROP_RECURRENCE_LAST_MEETING),
fromDate,
toDate
);
diff --git a/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQueryParams.java b/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQueryParams.java
index 72c2f3cb55..2fc30833cc 100644
--- a/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQueryParams.java
+++ b/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQueryParams.java
@@ -37,10 +37,13 @@ public class GetCalendarEntriesCannedQueryParams extends CalendarEntity
Long contentTypeQNameId,
Long fromDateQNameId,
Long toDateQNameId,
+ Long recurrenceRuleQNameId,
+ Long recurrenceLastMeetingQNameId,
Date entriesFromDate,
Date entriesToDate)
{
- super(null, nameQNameId, contentTypeQNameId, fromDateQNameId, toDateQNameId);
+ super(null, nameQNameId, contentTypeQNameId, fromDateQNameId,
+ toDateQNameId, recurrenceRuleQNameId, recurrenceLastMeetingQNameId);
this.sitesContainerNodeIds = sitesContainerNodeIds;
this.entriesFromDate = entriesFromDate;
diff --git a/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQueryTestHook.java b/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQueryTestHook.java
new file mode 100644
index 0000000000..798600ab97
--- /dev/null
+++ b/source/java/org/alfresco/repo/calendar/cannedqueries/GetCalendarEntriesCannedQueryTestHook.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005-2011 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.calendar.cannedqueries;
+
+import java.util.List;
+
+/**
+ * This class provides a way for a unit test to check up on what
+ * the {@link GetCalendarEntriesCannedQuery} does
+ *
+ * @author Nick Burch
+ * @since 4.0
+ */
+public interface GetCalendarEntriesCannedQueryTestHook
+{
+ void notifyComplete(List full, List filtered);
+}
diff --git a/source/java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelper.java b/source/java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelper.java
index 2380a59485..9e3caabaa1 100644
--- a/source/java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelper.java
+++ b/source/java/org/alfresco/service/cmr/calendar/CalendarRecurrenceHelper.java
@@ -88,20 +88,28 @@ public class CalendarRecurrenceHelper
*/
public static Map extractRecurrenceRule(CalendarEntry entry)
{
- String recurrence = entry.getRecurrenceRule();
- if(recurrence == null)
+ return extractRecurrenceRule(entry.getRecurrenceRule());
+ }
+ /**
+ * Returns the parsed calendar recurrence rule
+ * WARNING - Alfresco use only. Return type will likely shift to
+ * a real object in the near future
+ */
+ private static Map extractRecurrenceRule(String recurrenceRule)
+ {
+ if(recurrenceRule == null)
{
return null;
}
// Turn the string into a useful map
Map params = new HashMap();
- for(String rule : recurrence.split(";"))
+ for(String rule : recurrenceRule.split(";"))
{
String[] parts = rule.split("=");
if(parts.length != 2)
{
- logger.warn("Invalid rule '" + rule + "' in recurrence: " + recurrence);
+ logger.warn("Invalid rule '" + rule + "' in recurrence: " + recurrenceRule);
}
else
{
@@ -123,8 +131,25 @@ public class CalendarRecurrenceHelper
public static List getRecurrencesOnOrAfter(CalendarEntry entry, Date onOrAfter,
Date until, boolean firstOnly)
{
- String recurrence = entry.getRecurrenceRule();
- if(recurrence == null)
+ return getRecurrencesOnOrAfter(
+ entry.getRecurrenceRule(), entry.getStart(), entry.getEnd(),
+ entry.getLastRecurrence(), onOrAfter, until, firstOnly
+ );
+ }
+
+ /**
+ * For the given Calendar Entry, return its subsequent Recurrence on or after
+ * the specified date, until the given limit. If it doesn't have any recurrences
+ * on or after the start date (either no recurrence rules, or the last recurrence
+ * date is before then), null will be returned.
+ * If requested, can stop after the first hit
+ * @return The next recurrence on or after the given date, or null if there aren't any
+ */
+ public static List getRecurrencesOnOrAfter(String recurrenceRule, Date eventStart,
+ Date eventEnd, Date lastRecurrence,
+ Date onOrAfter, Date until, boolean firstOnly)
+ {
+ if(recurrenceRule == null)
{
// No recurrence
return null;
@@ -132,7 +157,6 @@ public class CalendarRecurrenceHelper
// See if we're past the last recurrence date
// Note - we rely on this being set for us, rather than checking the count
- Date lastRecurrence = entry.getLastRecurrence();
if(lastRecurrence != null && lastRecurrence.before(onOrAfter))
{
// Recurrence has stopped by this point
@@ -168,7 +192,7 @@ public class CalendarRecurrenceHelper
List dates = new ArrayList();
// Handle the different frequencies
- Map params = extractRecurrenceRule(entry);
+ Map params = extractRecurrenceRule(recurrenceRule);
if(params.containsKey("FREQ"))
{
String freq = params.get("FREQ");
@@ -187,7 +211,7 @@ public class CalendarRecurrenceHelper
}
Calendar currentDate = Calendar.getInstance();
- currentDate.setTime(entry.getStart());
+ currentDate.setTime(eventStart);
if ("DAILY".equals(freq))
{
@@ -215,7 +239,7 @@ public class CalendarRecurrenceHelper
}
else
{
- logger.warn("No frequency found, possible invalid rule? " + recurrence);
+ logger.warn("No frequency found, possible invalid rule? " + recurrenceRule);
return null;
}
}
@@ -434,7 +458,7 @@ public class CalendarRecurrenceHelper
currentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
}
- while(currentDate.before(onOrAfter))
+ while(currentDate.getTime().before(onOrAfter))
{
currentDate.set(Calendar.YEAR, currentDate.get(Calendar.YEAR) + 1);
currentDate.set(Calendar.MONTH, month);
@@ -444,7 +468,7 @@ public class CalendarRecurrenceHelper
{
if(until != null)
{
- if(currentDate.after(until))
+ if(currentDate.getTime().after(until))
{
break;
}