001: /*
002: * Copyright (c) 2001 - 2005 ivata limited.
003: * All rights reserved.
004: * -----------------------------------------------------------------------------
005: * ivata groupware may be redistributed under the GNU General Public
006: * License as published by the Free Software Foundation;
007: * version 2 of the License.
008: *
009: * These programs are free software; you can redistribute them and/or
010: * modify them under the terms of the GNU General Public License
011: * as published by the Free Software Foundation; version 2 of the License.
012: *
013: * These programs are distributed in the hope that they will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: *
017: * See the GNU General Public License in the file LICENSE.txt for more
018: * details.
019: *
020: * If you would like a copy of the GNU General Public License write to
021: *
022: * Free Software Foundation, Inc.
023: * 59 Temple Place - Suite 330
024: * Boston, MA 02111-1307, USA.
025: *
026: *
027: * To arrange commercial support and licensing, contact ivata at
028: * http://www.ivata.com/contact.jsp
029: * -----------------------------------------------------------------------------
030: * $Log: CalendarImpl.java,v $
031: * Revision 1.7 2005/10/11 18:58:58 colinmacleod
032: * Fixed some checkstyle and javadoc issues.
033: *
034: * Revision 1.6 2005/10/02 14:08:55 colinmacleod
035: * Added/improved log4j logging.
036: *
037: * Revision 1.5 2005/09/29 14:17:03 colinmacleod
038: * Split UserGroupDO off from GroupDO.
039: * Moved UserGroupDO, Right classes to security subproject (from
040: * addressbook).
041: * Centralized user right handling into Rights and RightsImpl.
042: *
043: * Revision 1.4 2005/09/14 15:12:03 colinmacleod
044: * Removed unused local and class variables.
045: * Added serialVersionUID.
046: *
047: * Revision 1.3 2005/04/10 20:43:45 colinmacleod
048: * Added new themes.
049: * Changed id type to String.
050: * Changed i tag to em and b tag to strong.
051: * Improved PicoContainerFactory with NanoContainer scripts.
052: *
053: * Revision 1.2 2005/04/09 17:19:16 colinmacleod
054: * Changed copyright text to GPL v2 explicitly.
055: *
056: * Revision 1.1.1.1 2005/03/10 17:47:42 colinmacleod
057: * Restructured ivata op around Hibernate/PicoContainer.
058: * Renamed ivata groupware.
059: *
060: * Revision 1.5 2004/11/12 18:17:26 colinmacleod
061: * Ordered imports.
062: *
063: * Revision 1.4 2004/11/12 16:08:08 colinmacleod
064: * Removed dependencies on SSLEXT.
065: * Moved Persistence classes to ivata masks.
066: *
067: * Revision 1.3 2004/11/03 15:49:49 colinmacleod
068: * Changed todo comments to TODO: all caps.
069: *
070: * Revision 1.2 2004/07/13 19:42:12 colinmacleod
071: * Moved project to POJOs from EJBs.
072: * Applied PicoContainer to services layer (replacing session EJBs).
073: * Applied Hibernate to persistence layer (replacing entity EJBs).
074: *
075: * Revision 1.1 2004/03/27 10:31:25 colinmacleod
076: * Split off business logic from remote facades to POJOs.
077: * -----------------------------------------------------------------------------
078: */
079: package com.ivata.groupware.business.calendar;
080:
081: import java.sql.Timestamp;
082: import java.util.ArrayList;
083: import java.util.Arrays;
084: import java.util.Collection;
085: import java.util.GregorianCalendar;
086: import java.util.Iterator;
087: import java.util.TimeZone;
088: import java.util.TreeSet;
089:
090: import org.apache.log4j.Logger;
091:
092: import com.ivata.groupware.admin.security.server.SecuritySession;
093: import com.ivata.groupware.business.BusinessLogic;
094: import com.ivata.groupware.business.calendar.event.EventDO;
095: import com.ivata.groupware.business.calendar.event.meeting.MeetingDO;
096: import com.ivata.groupware.business.calendar.event.publicholiday.PublicHolidayDO;
097: import com.ivata.groupware.container.persistence.TimestampDOHandling;
098: import com.ivata.mask.Mask;
099: import com.ivata.mask.MaskFactory;
100: import com.ivata.mask.persistence.PersistenceSession;
101: import com.ivata.mask.persistence.QueryPersistenceManager;
102: import com.ivata.mask.util.StringHandling;
103: import com.ivata.mask.util.SystemException;
104: import com.ivata.mask.validation.ValidationError;
105: import com.ivata.mask.validation.ValidationErrors;
106: import com.ivata.mask.validation.ValidationException;
107:
108: /**
109: * <p>
110: * Implementation of the calendar interface.
111: * </p>
112: * <copyDoc>Refer to {@link Calendar}.</copyDoc>
113: *
114: * @author Colin MacLeod
115: * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
116: * @since ivata groupware 0.11 (24-Mar-2004)
117: * @version $Revision: 1.7 $
118: */
119: public class CalendarImpl extends BusinessLogic implements Calendar {
120: /**
121: * <p>This class is used to sort the Events.</p>
122: */
123: private class EventComparator implements java.util.Comparator {
124: /**
125: * <p>Compare two objects (in this case, both are instances of
126: * {@link com.ivata.groupware.business.calendar.event.EventDO
127: * EventDO}) and return which is the higher priority.</p>
128: *
129: * @param o1 first instance of <code>Event</code> to be compared.
130: * @param o2 second instance of <code>Event</code> to be compared.
131: * @return A negative integer, or a positive integer as the first
132: * argument comes after, same as, or before the second.
133: */
134: public int compare(final Object o1, final Object o2) {
135: if (logger.isDebugEnabled()) {
136: logger.debug("compare(Object o1 = " + o1
137: + ", Object o2 = " + o2 + ") - start");
138: }
139:
140: EventDO event1 = (EventDO) o1;
141: EventDO event2 = (EventDO) o2;
142: long test1 = event1.getStart().getTime().getTime();
143: long test2 = event2.getStart().getTime().getTime();
144:
145: // note: purposely don't allow an equals case here!! If two are
146: // equal, then only one will appear in the final set
147: int returnInt;
148: if (test1 > test2) {
149: returnInt = 1;
150: } else {
151: returnInt = -1;
152: }
153: if (logger.isDebugEnabled()) {
154: logger
155: .debug("compare(Object, Object) - end - return value = "
156: + returnInt);
157: }
158: return returnInt;
159: }
160: }
161:
162: /**
163: * Logger for this class.
164: */
165: private static final Logger logger = Logger
166: .getLogger(CalendarImpl.class);
167:
168: /**
169: * Serialization version (for <code>Serializable</code> interface).
170: */
171: private static final long serialVersionUID = 1L;
172:
173: /**
174: * <copyDoc>Refer to {@link CalendarImpl()}.</copyDoc>
175: */
176: private MaskFactory maskFactory;
177:
178: /**
179: * Persistence manger used to store/retrieve data objects.
180: */
181: private QueryPersistenceManager persistenceManager;
182:
183: /**
184: * Construct a new calendar.
185: *
186: * @param persistenceManagerParam Used to persist calendar events.
187: * @param maskFactoryParam Creates appropriate masks for error reporting.
188: */
189: public CalendarImpl(
190: final QueryPersistenceManager persistenceManagerParam,
191: final MaskFactory maskFactoryParam) {
192: this .persistenceManager = persistenceManagerParam;
193: this .maskFactory = maskFactoryParam;
194: }
195:
196: /**
197: * {@inheritDoc}
198: *
199: * @param securitySession {@inheritDoc}
200: * @param event {@inheritDoc}
201: * @return {@inheritDoc}
202: * @throws SystemException {@inheritDoc}
203: */
204: public EventDO addEvent(final SecuritySession securitySession,
205: final EventDO event) throws SystemException {
206: if (logger.isDebugEnabled()) {
207: logger.debug("addEvent(SecuritySession securitySession = "
208: + securitySession + ", EventDO event = " + event
209: + ") - start");
210: }
211:
212: PersistenceSession persistenceSession = persistenceManager
213: .openSession(securitySession);
214: try {
215: // before creating the event, check we have reasonable data
216: ValidationErrors errors = validate(securitySession, event);
217: if (!errors.isEmpty()) {
218: throw new ValidationException(errors);
219: }
220: TimestampDOHandling.add(securitySession, event);
221: EventDO returnEventDO = (EventDO) persistenceManager.add(
222: persistenceSession, event);
223: if (logger.isDebugEnabled()) {
224: logger.debug("addEvent( - end - return value = "
225: + returnEventDO);
226: }
227: return returnEventDO;
228: } catch (Exception e) {
229: logger.error("addEvent(SecuritySession, EventDO)", e);
230:
231: persistenceSession.cancel();
232: throw new SystemException(e);
233: } finally {
234: persistenceSession.close();
235: }
236: }
237:
238: /**
239: * {@inheritDoc}
240: *
241: * @param securitySession {@inheritDoc}
242: * @param event {@inheritDoc}
243: * @return {@inheritDoc}
244: * @throws SystemException {@inheritDoc}
245: */
246: public EventDO amendEvent(final SecuritySession securitySession,
247: final EventDO event) throws SystemException {
248: if (logger.isDebugEnabled()) {
249: logger
250: .debug("amendEvent(SecuritySession securitySession = "
251: + securitySession
252: + ", EventDO event = "
253: + event + ") - start");
254: }
255:
256: PersistenceSession persistenceSession = persistenceManager
257: .openSession(securitySession);
258: try {
259: // before changing the event, check we have reasonable data
260: ValidationErrors errors = validate(securitySession, event);
261: if (!errors.isEmpty()) {
262: throw new ValidationException(errors);
263: }
264: TimestampDOHandling.amend(securitySession, event);
265: persistenceManager.amend(persistenceSession, event);
266:
267: if (logger.isDebugEnabled()) {
268: logger.debug("amendEvent - end - return value = "
269: + event);
270: }
271: return event;
272: } catch (Exception e) {
273: logger.error("amendEvent(SecuritySession, EventDO)", e);
274:
275: persistenceSession.cancel();
276: throw new SystemException(e);
277: } finally {
278: persistenceSession.close();
279: }
280: }
281:
282: /**
283: * {@inheritDoc}
284: *
285: * @param securitySession {@inheritDoc}
286: * @param id {@inheritDoc}
287: * @return {@inheritDoc}
288: * @throws SystemException {@inheritDoc}
289: */
290: public EventDO findEventByPrimaryKey(
291: final SecuritySession securitySession, final String id)
292: throws SystemException {
293: if (logger.isDebugEnabled()) {
294: logger
295: .debug("findEventByPrimaryKey(SecuritySession securitySession = "
296: + securitySession
297: + ", String id = "
298: + id
299: + ") - start");
300: }
301:
302: PersistenceSession persistenceSession = persistenceManager
303: .openSession(securitySession);
304: try {
305: EventDO returnEventDO = (EventDO) persistenceManager
306: .findByPrimaryKey(persistenceSession,
307: EventDO.class, id);
308: if (logger.isDebugEnabled()) {
309: logger
310: .debug("findEventByPrimaryKey - end - return value = "
311: + returnEventDO);
312: }
313: return returnEventDO;
314: } catch (Exception e) {
315: logger
316: .error(
317: "findEventByPrimaryKey(SecuritySession, String)",
318: e);
319:
320: persistenceSession.cancel();
321: throw new SystemException(e);
322: } finally {
323: persistenceSession.close();
324: }
325: }
326:
327: /**
328: * {@inheritDoc}
329: *
330: * @param securitySession {@inheritDoc}
331: * @param day {@inheritDoc}
332: * @return {@inheritDoc}
333: * @throws SystemException {@inheritDoc}
334: */
335: public Collection findEventsForDay(
336: final SecuritySession securitySession,
337: final java.util.Calendar day) throws SystemException {
338: if (logger.isDebugEnabled()) {
339: logger
340: .debug("findEventsForDay(SecuritySession securitySession = "
341: + securitySession
342: + ", java.util.Calendar day = "
343: + day
344: + ") - start");
345: }
346:
347: PersistenceSession persistenceSession = persistenceManager
348: .openSession(securitySession);
349: try {
350: GregorianCalendar tmpday = new GregorianCalendar();
351: TimeZone timeZone = day.getTimeZone();
352:
353: tmpday.setTime(day.getTime());
354: tmpday.setTimeZone(timeZone);
355: Timestamp start = new Timestamp(tmpday.getTime().getTime());
356:
357: // this move day field to next
358: tmpday.set(java.util.Calendar.DAY_OF_YEAR, tmpday
359: .get(java.util.Calendar.DAY_OF_YEAR) + 1);
360: Timestamp finish = new Timestamp(tmpday.getTime().getTime());
361: Collection events = persistenceManager.find(
362: persistenceSession, "calendarEventByStartFinish",
363: new Object[] { start, finish });
364: // sort the events TODO: I would rather use the database to sort
365: // but EJB QL still has no 'order by'
366: TreeSet sorted = new TreeSet(new EventComparator());
367:
368: sorted.addAll(events);
369: Collection returnItems = new ArrayList();
370: // either return all articles, or the count requested, whatever
371: // comes first
372: // TODO: I would rather use the database to limit the return but
373: // EJB QL still has no 'limit'
374: for (Iterator i = sorted.iterator(); i.hasNext();) {
375: EventDO eventDO = (EventDO) i.next();
376: // changing the timeZone for start and end, for correct sorting
377: // outside this method
378: java.util.Calendar tmpStart = eventDO.getStart();
379: if (tmpStart != null) {
380: tmpStart.setTimeZone(timeZone);
381: eventDO.setStart(tmpStart);
382: }
383: java.util.Calendar tmpFinish = eventDO.getFinish();
384: if (tmpFinish != null) {
385: tmpFinish.setTimeZone(timeZone);
386: eventDO.setFinish(tmpFinish);
387: }
388:
389: returnItems.add(eventDO);
390: }
391:
392: if (logger.isDebugEnabled()) {
393: logger.debug("findEventsForDay - end - return value = "
394: + returnItems);
395: }
396: return returnItems;
397: } catch (Exception e) {
398: logger
399: .error(
400: "findEventsForDay(SecuritySession, java.util.Calendar)",
401: e);
402:
403: persistenceSession.cancel();
404: throw new SystemException(e);
405: } finally {
406: persistenceSession.close();
407: }
408: }
409:
410: /**
411: * {@inheritDoc}
412: *
413: * @param securitySession {@inheritDoc}
414: * @param event {@inheritDoc}
415: * @throws SystemException {@inheritDoc}
416: */
417: public void removeEvent(final SecuritySession securitySession,
418: final EventDO event) throws SystemException {
419: if (logger.isDebugEnabled()) {
420: logger
421: .debug("removeEvent(SecuritySession securitySession = "
422: + securitySession
423: + ", EventDO event = "
424: + event + ") - start");
425: }
426:
427: PersistenceSession persistenceSession = persistenceManager
428: .openSession(securitySession);
429: try {
430: persistenceManager.remove(persistenceSession, event
431: .getClass(), event.getId());
432: } catch (Exception e) {
433: logger.error("removeEvent(SecuritySession, EventDO)", e);
434:
435: persistenceSession.cancel();
436: throw new SystemException(e);
437: } finally {
438: persistenceSession.close();
439: }
440:
441: if (logger.isDebugEnabled()) {
442: logger.debug("removeEvent(SecuritySession, EventDO) - end");
443: }
444: }
445:
446: /**
447: * {@inheritDoc}
448: *
449: * @param securitySession {@inheritDoc}
450: * @param eventDO {@inheritDoc}
451: * @return {@inheritDoc}
452: */
453: public ValidationErrors validate(
454: final SecuritySession securitySession, final EventDO eventDO) {
455: if (logger.isDebugEnabled()) {
456: logger.debug("validate(SecuritySession securitySession = "
457: + securitySession + ", EventDO eventDO = "
458: + eventDO + ") - start");
459: }
460:
461: ValidationErrors errors = new ValidationErrors();
462: Mask mask = maskFactory.getMask(EventDO.class);
463: String startFieldKey = "";
464: String finishFieldKey = "";
465:
466: // the field names depend on the type
467: if (eventDO instanceof PublicHolidayDO) {
468: startFieldKey = "event.field.startDate.publicHoliday";
469: finishFieldKey = "event.field.finishDate.publicHoliday";
470: } else {
471: startFieldKey = "event.field.startDate";
472: finishFieldKey = "event.field.finishDate";
473: }
474:
475: // start date is always mandatory
476: if (eventDO.getStart() == null) {
477: errors.add(new ValidationError("event",
478: Calendar.BUNDLE_PATH, mask.getField("start"),
479: "errors.required"));
480: }
481:
482: //start date/time must be before end date/time
483: if (eventDO.getStart() != null && eventDO.getFinish() != null
484: && eventDO.getStart().after(eventDO.getFinish())) {
485:
486: errors.add(new ValidationError("event",
487: Calendar.BUNDLE_PATH, mask.getField("finish"),
488: "errors.calendar.startAfterFinish", Arrays
489: .asList(new String[] { startFieldKey,
490: finishFieldKey })));
491: }
492:
493: // subject is always mandatory
494: if (StringHandling.isNullOrEmpty(eventDO.getSubject())) {
495: errors.add(new ValidationError("event",
496: Calendar.BUNDLE_PATH, mask.getField("subject"),
497: "errors.required"));
498: }
499:
500: if (logger.isDebugEnabled()) {
501: logger.debug("validate - end - return value = " + errors);
502: }
503: return errors;
504: }
505:
506: /**
507: * {@inheritDoc}
508: *
509: * @param securitySession {@inheritDoc}
510: * @param meetingDO {@inheritDoc}
511: * @return {@inheritDoc}
512: */
513: public ValidationErrors validate(
514: final SecuritySession securitySession,
515: final MeetingDO meetingDO) {
516: if (logger.isDebugEnabled()) {
517: logger.debug("validate(SecuritySession securitySession = "
518: + securitySession + ", MeetingDO meetingDO = "
519: + meetingDO + ") - start");
520: }
521:
522: ValidationErrors errors = validate(securitySession,
523: (EventDO) meetingDO);
524: Mask mask = maskFactory.getMask(MeetingDO.class);
525:
526: // location is always mandatory
527: if (StringHandling.isNullOrEmpty(meetingDO.getLocation())) {
528: errors.add(new ValidationError("event",
529: Calendar.BUNDLE_PATH, mask.getField("location"),
530: "errors.required"));
531: }
532:
533: if (logger.isDebugEnabled()) {
534: logger.debug("validate - end - return value = " + errors);
535: }
536: return errors;
537: }
538:
539: }
|