001    /*
002     * The MIT License
003     * Copyright (c) 2012 Microsoft Corporation
004     *
005     * Permission is hereby granted, free of charge, to any person obtaining a copy
006     * of this software and associated documentation files (the "Software"), to deal
007     * in the Software without restriction, including without limitation the rights
008     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
009     * copies of the Software, and to permit persons to whom the Software is
010     * furnished to do so, subject to the following conditions:
011     *
012     * The above copyright notice and this permission notice shall be included in
013     * all copies or substantial portions of the Software.
014     *
015     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
016     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
017     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
018     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
019     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
020     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
021     * THE SOFTWARE.
022     */
023    
024    package microsoft.exchange.webservices.data.core.service.item;
025    
026    import microsoft.exchange.webservices.data.attribute.ServiceObjectDefinition;
027    import microsoft.exchange.webservices.data.core.ExchangeService;
028    import microsoft.exchange.webservices.data.core.PropertySet;
029    import microsoft.exchange.webservices.data.core.XmlElementNames;
030    import microsoft.exchange.webservices.data.core.service.response.AcceptMeetingInvitationMessage;
031    import microsoft.exchange.webservices.data.core.service.response.DeclineMeetingInvitationMessage;
032    import microsoft.exchange.webservices.data.core.service.schema.AppointmentSchema;
033    import microsoft.exchange.webservices.data.core.service.schema.MeetingRequestSchema;
034    import microsoft.exchange.webservices.data.core.service.schema.ServiceObjectSchema;
035    import microsoft.exchange.webservices.data.core.enumeration.service.calendar.AppointmentType;
036    import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
037    import microsoft.exchange.webservices.data.core.enumeration.property.LegacyFreeBusyStatus;
038    import microsoft.exchange.webservices.data.core.enumeration.service.MeetingRequestType;
039    import microsoft.exchange.webservices.data.core.enumeration.property.MeetingResponseType;
040    import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException;
041    import microsoft.exchange.webservices.data.misc.CalendarActionResults;
042    import microsoft.exchange.webservices.data.misc.TimeSpan;
043    import microsoft.exchange.webservices.data.property.complex.AttendeeCollection;
044    import microsoft.exchange.webservices.data.property.complex.DeletedOccurrenceInfoCollection;
045    import microsoft.exchange.webservices.data.property.complex.EmailAddress;
046    import microsoft.exchange.webservices.data.property.complex.ItemAttachment;
047    import microsoft.exchange.webservices.data.property.complex.ItemCollection;
048    import microsoft.exchange.webservices.data.property.complex.ItemId;
049    import microsoft.exchange.webservices.data.property.complex.OccurrenceInfo;
050    import microsoft.exchange.webservices.data.property.complex.OccurrenceInfoCollection;
051    import microsoft.exchange.webservices.data.property.complex.recurrence.pattern.Recurrence;
052    import microsoft.exchange.webservices.data.property.complex.time.TimeZoneDefinition;
053    import org.apache.commons.logging.Log;
054    import org.apache.commons.logging.LogFactory;
055    
056    import java.util.Date;
057    
058    /**
059     * Represents a meeting request that an attendee can accept
060     * or decline. Properties available on meeting
061     * request are defined in the MeetingRequestSchema class.
062     */
063    @ServiceObjectDefinition(xmlElementName = XmlElementNames.MeetingRequest)
064    public class MeetingRequest extends MeetingMessage implements ICalendarActionProvider {
065    
066      private static final Log LOG = LogFactory.getLog(MeetingRequest.class);
067    
068      /**
069       * Initializes a new instance of the class.
070       *
071       * @param parentAttachment The parent attachment
072       * @throws Exception throws Exception
073       */
074      public MeetingRequest(ItemAttachment parentAttachment) throws Exception {
075        super(parentAttachment);
076      }
077    
078      /**
079       * Initializes a new instance of the class.
080       *
081       * @param service EWS service to which this object belongs.
082       * @throws Exception throws Exception
083       */
084      public MeetingRequest(ExchangeService service) throws Exception {
085        super(service);
086      }
087    
088      /**
089       * Binds to an existing meeting response and loads the specified set of
090       * property. Calling this method results in a call to EWS.
091       *
092       * @param service     The service to use to bind to the meeting request.
093       * @param id          The Id of the meeting request to bind to.
094       * @param propertySet The set of property to load.
095       * @return A MeetingResponse instance representing the meeting request
096       * corresponding to the specified Id.
097       */
098      public static MeetingRequest bind(ExchangeService service, ItemId id,
099          PropertySet propertySet) {
100        try {
101          return service.bindToItem(MeetingRequest.class, id, propertySet);
102        } catch (Exception e) {
103          LOG.error(e);
104          return null;
105        }
106      }
107    
108      /**
109       * Binds to an existing meeting response and loads the specified set of
110       * property. Calling this method results in a call to EWS.
111       *
112       * @param service The service to use to bind to the meeting request.
113       * @param id      The Id of the meeting request to bind to.
114       * @return A MeetingResponse instance representing the meeting request
115       * corresponding to the specified Id.
116       */
117      public static MeetingRequest bind(ExchangeService service, ItemId id) {
118        return MeetingRequest.bind(service, id, PropertySet
119            .getFirstClassProperties());
120      }
121    
122      /**
123       * Internal method to return the schema associated with this type of object.
124       *
125       * @return The schema associated with this type of object.
126       */
127      @Override public ServiceObjectSchema getSchema() {
128        return MeetingRequestSchema.Instance;
129      }
130    
131      /**
132       * Gets the minimum required server version.
133       *
134       * @return Earliest Exchange version in which this service object type is
135       * supported.
136       */
137      @Override public ExchangeVersion getMinimumRequiredServerVersion() {
138        return ExchangeVersion.Exchange2007_SP1;
139      }
140    
141      /**
142       * Creates a local meeting acceptance message that can be customized and
143       * sent.
144       *
145       * @param tentative Specifies whether the meeting will be tentatively accepted.
146       * @return An AcceptMeetingInvitationMessage representing the meeting
147       * acceptance message.
148       */
149      public AcceptMeetingInvitationMessage createAcceptMessage(boolean
150          tentative) {
151        try {
152          return new AcceptMeetingInvitationMessage(this, tentative);
153        } catch (Exception e) {
154          LOG.error(e);
155          return null;
156        }
157      }
158    
159      /**
160       * Creates a local meeting declination message that can be customized and
161       * sent.
162       *
163       * @return A DeclineMeetingInvitation representing the meeting declination
164       * message.
165       */
166      public DeclineMeetingInvitationMessage createDeclineMessage() {
167        try {
168          return new DeclineMeetingInvitationMessage(this);
169        } catch (Exception e) {
170          LOG.error(e);
171          return null;
172        }
173      }
174    
175      /**
176       * Accepts the meeting. Calling this method results in a call to EWS.
177       *
178       * @param sendResponse Indicates whether to send a response to the organizer.
179       * @return A CalendarActionResults object containing the various item that
180       * were created or modified as a results of this operation.
181       * @throws Exception throws Exception
182       */
183      public CalendarActionResults accept(boolean sendResponse) throws Exception {
184        return this.internalAccept(false, sendResponse);
185      }
186    
187      /**
188       * Tentatively accepts the meeting. Calling this method results in a call to
189       * EWS.
190       *
191       * @param sendResponse Indicates whether to send a response to the organizer.
192       * @return A CalendarActionResults object containing the various item that
193       * were created or modified as a results of this operation.
194       * @throws Exception throws Exception
195       */
196      public CalendarActionResults acceptTentatively(boolean sendResponse)
197          throws Exception {
198        return this.internalAccept(true, sendResponse);
199      }
200    
201      /**
202       * Accepts the meeting.
203       *
204       * @param tentative    True if tentative accept.
205       * @param sendResponse Indicates whether to send a response to the organizer.
206       * @return A CalendarActionResults object containing the various item that
207       * were created or modified as a results of this operation.
208       * @throws Exception throws Exception
209       */
210      protected CalendarActionResults internalAccept(boolean tentative,
211          boolean sendResponse) throws Exception {
212        AcceptMeetingInvitationMessage accept = this
213            .createAcceptMessage(tentative);
214    
215        if (sendResponse) {
216          return accept.calendarSendAndSaveCopy();
217        } else {
218          return accept.calendarSave();
219    
220        }
221      }
222    
223      /**
224       * Declines the meeting invitation. Calling this method results in a call to
225       * EWS.
226       *
227       * @param sendResponse Indicates whether to send a response to the organizer.
228       * @return A CalendarActionResults object containing the various item that
229       * were created or modified as a results of this operation.
230       * @throws Exception throws Exception
231       */
232      public CalendarActionResults decline(boolean sendResponse)
233          throws Exception {
234        DeclineMeetingInvitationMessage decline = this.createDeclineMessage();
235    
236        if (sendResponse) {
237          return decline.calendarSendAndSaveCopy();
238        } else {
239          return decline.calendarSave();
240        }
241      }
242    
243      /**
244       * Gets the type of this meeting request.
245       *
246       * @return the meeting request type
247       * @throws ServiceLocalException the service local exception
248       */
249      public MeetingRequestType getMeetingRequestType()
250          throws ServiceLocalException {
251        return getPropertyBag().getObjectFromPropertyDefinition(
252            MeetingRequestSchema.MeetingRequestType);
253      }
254    
255      /**
256       * Gets the a value representing the intended free/busy status of the
257       * meeting.
258       *
259       * @return the intended free busy status
260       * @throws ServiceLocalException the service local exception
261       */
262      public LegacyFreeBusyStatus getIntendedFreeBusyStatus()
263          throws ServiceLocalException {
264        return getPropertyBag().getObjectFromPropertyDefinition(
265            MeetingRequestSchema.IntendedFreeBusyStatus);
266      }
267    
268      /**
269       * Gets the start time of the appointment.
270       *
271       * @return the start
272       * @throws ServiceLocalException the service local exception
273       */
274      public Date getStart() throws ServiceLocalException {
275        return getPropertyBag().getObjectFromPropertyDefinition(
276            AppointmentSchema.Start);
277      }
278    
279      /**
280       * Gets the end time of the appointment.
281       *
282       * @return the end
283       * @throws ServiceLocalException the service local exception
284       */
285      public Date getEnd() throws ServiceLocalException {
286        return getPropertyBag().getObjectFromPropertyDefinition(
287            AppointmentSchema.End);
288      }
289    
290      /**
291       * Gets the original start time of the appointment.
292       *
293       * @return the original start
294       * @throws ServiceLocalException the service local exception
295       */
296      public Date getOriginalStart() throws ServiceLocalException {
297        return getPropertyBag().getObjectFromPropertyDefinition(
298            AppointmentSchema.OriginalStart);
299      }
300    
301      /**
302       * Gets a value indicating whether this appointment is an all day event.
303       *
304       * @return the checks if is all day event
305       * @throws ServiceLocalException the service local exception
306       */
307      public boolean getIsAllDayEvent() throws ServiceLocalException {
308        return getPropertyBag().getObjectFromPropertyDefinition(
309            AppointmentSchema.IsAllDayEvent) != null;
310      }
311    
312      /**
313       * Gets a value indicating the free/busy status of the owner of this
314       * appointment.
315       *
316       * @return the legacy free busy status
317       * @throws ServiceLocalException the service local exception
318       */
319      public LegacyFreeBusyStatus legacyFreeBusyStatus()
320          throws ServiceLocalException {
321        return getPropertyBag().getObjectFromPropertyDefinition(
322            AppointmentSchema.LegacyFreeBusyStatus);
323      }
324    
325      /**
326       * Gets  the location of this appointment.
327       *
328       * @return the location
329       * @throws ServiceLocalException the service local exception
330       */
331      public String getLocation() throws ServiceLocalException {
332        return getPropertyBag().getObjectFromPropertyDefinition(
333            AppointmentSchema.Location);
334      }
335    
336      /**
337       * Gets a text indicating when this appointment occurs. The text returned by
338       * When is localized using the Exchange Server culture or using the culture
339       * specified in the PreferredCulture property of the ExchangeService object
340       * this appointment is bound to.
341       *
342       * @return the when
343       * @throws ServiceLocalException the service local exception
344       */
345      public String getWhen() throws ServiceLocalException {
346        return getPropertyBag().getObjectFromPropertyDefinition(
347            AppointmentSchema.When);
348      }
349    
350      /**
351       * Gets a value indicating whether the appointment is a meeting.
352       *
353       * @return the checks if is meeting
354       * @throws ServiceLocalException the service local exception
355       */
356      public boolean getIsMeeting() throws ServiceLocalException {
357        return getPropertyBag().getObjectFromPropertyDefinition(
358            AppointmentSchema.IsMeeting) != null;
359      }
360    
361      /**
362       * Gets a value indicating whether the appointment has been cancelled.
363       *
364       * @return the checks if is cancelled
365       * @throws ServiceLocalException the service local exception
366       */
367      public boolean getIsCancelled() throws ServiceLocalException {
368        return getPropertyBag().getObjectFromPropertyDefinition(
369            AppointmentSchema.IsCancelled) != null;
370      }
371    
372      /**
373       * Gets a value indicating whether the appointment is recurring.
374       *
375       * @return the checks if is recurring
376       * @throws ServiceLocalException the service local exception
377       */
378      public boolean getIsRecurring() throws ServiceLocalException {
379        return getPropertyBag().getObjectFromPropertyDefinition(
380            AppointmentSchema.IsRecurring) != null;
381      }
382    
383      /**
384       * Gets a value indicating whether the meeting request has already been
385       * sent.
386       *
387       * @return the meeting request was sent
388       * @throws ServiceLocalException the service local exception
389       */
390      public boolean getMeetingRequestWasSent() throws ServiceLocalException {
391        return getPropertyBag().getObjectFromPropertyDefinition(
392            AppointmentSchema.MeetingRequestWasSent) != null;
393      }
394    
395      /**
396       * Gets a value indicating the type of this appointment.
397       *
398       * @return the appointment type
399       * @throws ServiceLocalException the service local exception
400       */
401      public AppointmentType getAppointmentType() throws ServiceLocalException {
402        return getPropertyBag().getObjectFromPropertyDefinition(
403            AppointmentSchema.AppointmentType);
404      }
405    
406      /**
407       * Gets a value indicating what was the last response of the user that
408       * loaded this meeting.
409       *
410       * @return the my response type
411       * @throws ServiceLocalException the service local exception
412       */
413      public MeetingResponseType getMyResponseType()
414          throws ServiceLocalException {
415        return getPropertyBag().getObjectFromPropertyDefinition(
416            AppointmentSchema.MyResponseType);
417      }
418    
419      /**
420       * Gets the organizer of this meeting.
421       *
422       * @return the organizer
423       * @throws ServiceLocalException the service local exception
424       */
425      public EmailAddress getOrganizer() throws ServiceLocalException {
426        return getPropertyBag().getObjectFromPropertyDefinition(
427            AppointmentSchema.Organizer);
428      }
429    
430      /**
431       * Gets a list of required attendees for this meeting.
432       *
433       * @return the required attendees
434       * @throws ServiceLocalException the service local exception
435       */
436      public AttendeeCollection getRequiredAttendees()
437          throws ServiceLocalException {
438        return getPropertyBag().getObjectFromPropertyDefinition(
439            AppointmentSchema.RequiredAttendees);
440      }
441    
442      /**
443       * Gets a list of optional attendeed for this meeting.
444       *
445       * @return the optional attendees
446       * @throws ServiceLocalException the service local exception
447       */
448      public AttendeeCollection getOptionalAttendees()
449          throws ServiceLocalException {
450        return getPropertyBag().getObjectFromPropertyDefinition(
451            AppointmentSchema.OptionalAttendees);
452      }
453    
454      /**
455       * Gets a list of resources for this meeting.
456       *
457       * @return the resources
458       * @throws ServiceLocalException the service local exception
459       */
460      public AttendeeCollection getResources() throws ServiceLocalException {
461        return getPropertyBag().getObjectFromPropertyDefinition(
462            AppointmentSchema.Resources);
463      }
464    
465      /**
466       * Gets the number of calendar entries that conflict with
467       * this appointment in the authenticated user's calendar.
468       *
469       * @return the conflicting meeting count
470       * @throws NumberFormatException the number format exception
471       * @throws ServiceLocalException the service local exception
472       */
473      public int getConflictingMeetingCount() throws NumberFormatException,
474          ServiceLocalException {
475        return (Integer.parseInt(this.getPropertyBag()
476            .getObjectFromPropertyDefinition(
477                AppointmentSchema.ConflictingMeetingCount).toString()));
478      }
479    
480      /**
481       * Gets the number of calendar entries that are adjacent to
482       * this appointment in the authenticated user's calendar.
483       *
484       * @return the adjacent meeting count
485       * @throws NumberFormatException the number format exception
486       * @throws ServiceLocalException the service local exception
487       */
488      public int getAdjacentMeetingCount() throws NumberFormatException,
489          ServiceLocalException {
490        return (Integer.parseInt(this.getPropertyBag()
491            .getObjectFromPropertyDefinition(
492                AppointmentSchema.AdjacentMeetingCount).toString()));
493      }
494    
495      /**
496       * Gets a list of meetings that conflict with
497       * this appointment in the authenticated user's calendar.
498       *
499       * @return the conflicting meetings
500       * @throws ServiceLocalException the service local exception
501       */
502      public ItemCollection<Appointment> getConflictingMeetings()
503          throws ServiceLocalException {
504        return getPropertyBag().getObjectFromPropertyDefinition(
505            AppointmentSchema.ConflictingMeetings);
506      }
507    
508      /**
509       * Gets a list of meetings that are adjacent with this
510       * appointment in the authenticated user's calendar.
511       *
512       * @return the adjacent meetings
513       * @throws ServiceLocalException the service local exception
514       */
515      public ItemCollection<Appointment> getAdjacentMeetings()
516          throws ServiceLocalException {
517        return getPropertyBag().getObjectFromPropertyDefinition(
518            AppointmentSchema.AdjacentMeetings);
519      }
520    
521      /**
522       * Gets the duration of this appointment.
523       *
524       * @return the duration
525       * @throws ServiceLocalException the service local exception
526       */
527      public TimeSpan getDuration() throws ServiceLocalException {
528        return getPropertyBag().getObjectFromPropertyDefinition(
529            AppointmentSchema.Duration);
530      }
531    
532      /**
533       * Gets the name of the time zone this appointment is defined in.
534       *
535       * @return the time zone
536       * @throws ServiceLocalException the service local exception
537       */
538      public String getTimeZone() throws ServiceLocalException {
539        return getPropertyBag().getObjectFromPropertyDefinition(
540            AppointmentSchema.TimeZone);
541      }
542    
543      /**
544       * Gets the time when the attendee replied to the meeting request.
545       *
546       * @return the appointment reply time
547       * @throws ServiceLocalException the service local exception
548       */
549      public Date getAppointmentReplyTime() throws ServiceLocalException {
550        return getPropertyBag().getObjectFromPropertyDefinition(
551            AppointmentSchema.AppointmentReplyTime);
552      }
553    
554      /**
555       * Gets the sequence number of this appointment.
556       *
557       * @return the appointment sequence number
558       * @throws NumberFormatException the number format exception
559       * @throws ServiceLocalException the service local exception
560       */
561      public int getAppointmentSequenceNumber() throws NumberFormatException,
562          ServiceLocalException {
563        return (Integer
564            .parseInt(this.getPropertyBag()
565                .getObjectFromPropertyDefinition(
566                    AppointmentSchema.AppointmentSequenceNumber)
567                .toString()));
568      }
569    
570      /**
571       * Gets the state of this appointment.
572       *
573       * @return the appointment state
574       * @throws NumberFormatException the number format exception
575       * @throws ServiceLocalException the service local exception
576       */
577      public int getAppointmentState() throws NumberFormatException,
578          ServiceLocalException {
579        return (Integer.parseInt(this.getPropertyBag()
580            .getObjectFromPropertyDefinition(
581                AppointmentSchema.AppointmentState).toString()));
582      }
583    
584      /**
585       * Gets the recurrence pattern for this meeting request.
586       *
587       * @return the recurrence
588       * @throws ServiceLocalException the service local exception
589       */
590      public Recurrence getRecurrence() throws ServiceLocalException {
591        return getPropertyBag().getObjectFromPropertyDefinition(
592            AppointmentSchema.Recurrence);
593      }
594    
595      /**
596       * Gets an OccurrenceInfo identifying the first occurrence of this meeting.
597       *
598       * @return the first occurrence
599       * @throws ServiceLocalException the service local exception
600       */
601      public OccurrenceInfo getFirstOccurrence() throws ServiceLocalException {
602        return getPropertyBag().getObjectFromPropertyDefinition(
603            AppointmentSchema.FirstOccurrence);
604      }
605    
606      /**
607       * Gets an OccurrenceInfo identifying the last occurrence of this meeting.
608       *
609       * @return the last occurrence
610       * @throws ServiceLocalException the service local exception
611       */
612      public OccurrenceInfo getLastOccurrence() throws ServiceLocalException {
613        return getPropertyBag().getObjectFromPropertyDefinition(
614            AppointmentSchema.FirstOccurrence);
615      }
616    
617      /**
618       * Gets a list of modified occurrences for this meeting.
619       *
620       * @return the modified occurrences
621       * @throws ServiceLocalException the service local exception
622       */
623      public OccurrenceInfoCollection getModifiedOccurrences()
624          throws ServiceLocalException {
625        return getPropertyBag().getObjectFromPropertyDefinition(
626            AppointmentSchema.ModifiedOccurrences);
627      }
628    
629      /**
630       * Gets a list of deleted occurrences for this meeting.
631       *
632       * @return the deleted occurrences
633       * @throws ServiceLocalException the service local exception
634       */
635      public DeletedOccurrenceInfoCollection getDeletedOccurrences()
636          throws ServiceLocalException {
637        return getPropertyBag().getObjectFromPropertyDefinition(
638            AppointmentSchema.DeletedOccurrences);
639      }
640    
641      /**
642       * Gets  time zone of the start property of this meeting request.
643       *
644       * @return the start time zone
645       * @throws ServiceLocalException the service local exception
646       */
647      public TimeZoneDefinition getStartTimeZone() throws ServiceLocalException {
648        return getPropertyBag().getObjectFromPropertyDefinition(
649            AppointmentSchema.StartTimeZone);
650      }
651    
652      /**
653       * Gets  time zone of the end property of this meeting request.
654       *
655       * @return the end time zone
656       * @throws ServiceLocalException the service local exception
657       */
658      public TimeZoneDefinition getEndTimeZone() throws ServiceLocalException {
659        return getPropertyBag().getObjectFromPropertyDefinition(
660            AppointmentSchema.EndTimeZone);
661      }
662    
663      /**
664       * Gets the type of conferencing that will be used during the meeting.
665       *
666       * @return the conference type
667       * @throws NumberFormatException the number format exception
668       * @throws ServiceLocalException the service local exception
669       */
670      public int getConferenceType() throws NumberFormatException,
671          ServiceLocalException {
672        return (Integer.parseInt(this.getPropertyBag()
673            .getObjectFromPropertyDefinition(
674                AppointmentSchema.ConferenceType).toString()));
675      }
676    
677      /**
678       * Gets a value indicating whether new time
679       * proposals are allowed for attendees of this meeting.
680       *
681       * @return the allow new time proposal
682       * @throws ServiceLocalException the service local exception
683       */
684      public boolean getAllowNewTimeProposal() throws ServiceLocalException {
685        return getPropertyBag().<Boolean>getObjectFromPropertyDefinition(
686            AppointmentSchema.AllowNewTimeProposal);
687      }
688    
689      /**
690       * Gets a value indicating whether this is an online meeting.
691       *
692       * @return the checks if is online meeting
693       * @throws ServiceLocalException the service local exception
694       */
695      public boolean getIsOnlineMeeting() throws ServiceLocalException {
696        return getPropertyBag().<Boolean>getObjectFromPropertyDefinition(
697            AppointmentSchema.IsOnlineMeeting);
698      }
699    
700      /**
701       * Gets the URL of the meeting workspace. A meeting
702       * workspace is a shared Web site for
703       * planning meetings and tracking results.
704       *
705       * @return the meeting workspace url
706       * @throws ServiceLocalException the service local exception
707       */
708      public String getMeetingWorkspaceUrl() throws ServiceLocalException {
709        return getPropertyBag().getObjectFromPropertyDefinition(
710            AppointmentSchema.MeetingWorkspaceUrl);
711      }
712    
713      /**
714       * Gets the URL of the Microsoft NetShow online meeting.
715       *
716       * @return the net show url
717       * @throws ServiceLocalException the service local exception
718       */
719      public String getNetShowUrl() throws ServiceLocalException {
720        return getPropertyBag().getObjectFromPropertyDefinition(
721            AppointmentSchema.NetShowUrl);
722      }
723    }