Hi,
Attached is a patch against CalendarPortlet rel-1-patches branch. The
pom assumes that you have available
<groupId>microsoft</groupId>
<artifactId>EWSJavaAPI</artifactId>
<version>1.1.5</version>
Available from
http://archive.msdn.microsoft.__com/ewsjavaapi/Release/__ProjectReleases.aspx?__ReleaseId=5754
and
<groupId>jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.3.15</version>
Available from http://maven.jahia.org/maven2/
Auto-discovery was my main sticking point. My pain was that I wanted the
attributes used for authentication to be configurable. I.e. we use
uid+password for Stuff (in house Exchange 2010 server) and
email+password for Students (Hosted Live@EDU). Having auto-discovery an
initialization service seemed sensible, but due to the different
staff/student configurations I found myself needing to have 2
initialization services. So I opted to do the auto-discovery within the
adaptor on first use. (Also I would like the discovered url to be cached
longer then the session, but couldn't be sure I could store a
preference. As the adaptor API specifies PortletRequest).
Comments/feedback welcomed.
-- Anthony.
On 10/11/11 15:24, Anthony Colebourne wrote:
> Hi,
>
> When I tried the dropping 2010 into the JAX-B section of the pom, I did
> also droped in the xsd files. I cannot remember the exact issues but I
> didn't make any progress :-(
>
> 2 issues lead me to use a local copy of the wsdl and xsd files, 1) the
> missing endpoint and 2) access to the wsdl (at build time, although
> JAX-WS seems to also need access at runtime).
>
> I did have success with the JAX-WS maven plugin, but struggled when
> actually using it.
>
> On the negative side, I don't "think" that the EWSJavaAPI supports
> impersonation. This might be an issue for folks who do not have access
> to the users password.
>
> Cheers,
> Anthony.
>
>
> On 10/11/11 15:03, Jen Bourey wrote:
>> You actually don't really need a local WSDL; we added it to the project
>> because the one that's deployed in a lot of Microsoft implementations by
>> default is missing a key XML snippet and doesn't actually work. If your
>> WSDL works, you could just point it to the live one. My understanding is
>> that 2007 and 2010 are actually very close. If there are differences,
>> you might need to update the two XSD files with the ones on your server.
>> If you're interested in trying to get that working against your campus
>> server, let me know if there's anything we can do to help.
>>
>> Anyway, about the MS dependency: It's great to hear that that's easy to
>> use. I took a look at the license, and it looks like the Microsoft
>> license is on our A list, so including it in the project wouldn't be an
>> issue from a licensing perspective.
>>
>> - Jen
>>
>> On Thu, Nov 10, 2011 at 9:32 AM, Anthony Colebourne
>> <anthony.colebou...@manchester.ac.uk
>> <mailto:anthony.colebou...@manchester.ac.uk>> wrote:
>>
>> Hi,
>>
>> I believe the current Jasig Exchange integrations are Exchange2008
>> not 2010? (I dropped my local version of the 2010 wsdl into the
>> calendar's maven config but things went badly wrong).
>>
>> I too have a JAX-WS generated implementation of the webservice, but
>> found it very complicated to use.
>>
>> In contrast the EWSJavaAPI is "ridiculously simple". Within
>> practically 10 mins on a test bed I was able to pull all the data I
>> needed from Email, Calendar, Tasks and Contacts with no local wsdl
>> or maven plugin to manage.
>>
>> -- Anthony.
>>
>>
>> On 10/11/11 14:22, Jen Bourey wrote:
>>
>> Hey Anthony,
>>
>> The calendar portlet actually already has an Exchange adapter
>> out of the
>> box. It uses spring-ws to connect to the services, which seems
>> not too
>> require too much custom code. I know Nick is also currently
>> doing some
>> EWS integration into the Scheduler too. Maybe there's an
>> opportunity to
>> create some documentation and best practices around Exchange
>> integration? How've you found the Java library your'e using to
>> be so far?
>>
>> - Jen
>>
>> On Thu, Nov 10, 2011 at 9:21 AM, Jen Bourey
>> <jennifer.bou...@gmail.com <mailto:jennifer.bou...@gmail.com>
>> <mailto:jennifer.bourey@gmail.__com
>> <mailto:jennifer.bou...@gmail.com>>> wrote:
>>
>> Hey Anthony,
>>
>> The calendar portlet actually already has an Exchange adapter out of
>> the box. It uses spring-ws to connect to the services, which seems
>> not too require too much custom code. I know Nick is also currently
>> doing some EWS integration into the Scheduler too. Maybe there's an
>> opportunity to create some documentation and best practices around
>> Exchange integration? How've you found the Java library your'e using
>> to be so far?
>>
>> - Jen
>>
>>
>>
>> On Nov 9, 2011, at 7:31 PM, Anthony Colebourne wrote:
>>
>> cc: licens...@jasig.org <mailto:licens...@jasig.org>
>> <mailto:licens...@jasig.org <mailto:licens...@jasig.org>>
>>
>>
>> Hi,
>>
>> I want to contribute some Exchange 2010 adapters (development in
>> progress).
>> * CalendarPortlet
>> * NotificationsPortlet
>> Also in future
>> * ContactsPortlet
>> * EmailPreviewPortlet
>> * ScheduleAssistant
>>
>> The jar is available form
>> http://archive.msdn.microsoft.__com/ewsjavaapi/Release/__ProjectReleases.aspx?__ReleaseId=5754
>>
>> <http://archive.msdn.microsoft.com/ewsjavaapi/Release/ProjectReleases.aspx?ReleaseId=5754>
>>
>>
>> Would it be possible to get this into Jasig's Maven repo?
>>
>> It has the following dependencies:
>> Apache Commons HttpClient 3.1
>> Apache Commons Codec 1.4
>> Apache Commons Logging 1.1.1
>> JCIFS 1.3.15
>>
>> JCIFS is available from http://maven.jahia.org/maven2/
>> Others available in Maven central.
>>
>> Could these dependencies also be made available?
>>
>> Thanks,
>> Anthony.
>>
>> --
>> You are currently subscribed to uportal-dev@lists.ja-sig.org
>> <mailto:uportal-dev@lists.ja-sig.org>
>> <mailto:uportal-...@lists.ja-__sig.org
>> <mailto:uportal-dev@lists.ja-sig.org>> as:
>> jennifer.bou...@gmail.com <mailto:jennifer.bou...@gmail.com>
>> <mailto:jennifer.bourey@gmail.__com
>> <mailto:jennifer.bou...@gmail.com>>
>>
>> To unsubscribe, change settings or access archives, see
>> http://www.ja-sig.org/wiki/__display/JSG/uportal-dev
>> <http://www.ja-sig.org/wiki/display/JSG/uportal-dev>
>>
>>
>>
>>
>>
>> --
>> Jen Bourey
>>
>> --
>>
>> You are currently subscribed to uportal-dev@lists.ja-sig.org
>> <mailto:uportal-dev@lists.ja-sig.org> as:
>> anthony.colebourne@manchester.__ac.uk
>> <mailto:anthony.colebou...@manchester.ac.uk>
>>
>> To unsubscribe, change settings or access archives, see
>> http://www.ja-sig.org/wiki/__display/JSG/uportal-dev
>> <http://www.ja-sig.org/wiki/display/JSG/uportal-dev>
>>
>>
>>
>>
>> --
>> Jen Bourey
>>
>> --
>>
>> You are currently subscribed to uportal-dev@lists.ja-sig.org as:
>> anthony.colebou...@manchester.ac.uk
>> To unsubscribe, change settings or access archives, see
>> http://www.ja-sig.org/wiki/display/JSG/uportal-dev
>>
>
--
You are currently subscribed to uportal-dev@lists.ja-sig.org as:
arch...@mail-archive.com
To unsubscribe, change settings or access archives, see
http://www.ja-sig.org/wiki/display/JSG/uportal-dev
### Eclipse Workspace Patch 1.0
#P CalendarPortlet-JASIG
Index: src/main/webapp/WEB-INF/context/calendarContext.xml
===================================================================
--- src/main/webapp/WEB-INF/context/calendarContext.xml (revision 25508)
+++ src/main/webapp/WEB-INF/context/calendarContext.xml (working copy)
@@ -100,6 +100,19 @@
p:emailAttribute="mail">
</bean-->
+ <!--
+ | EXCHANGE 2010 SUPPORT
+ |
+ | Uncomment the following section to enable Exchange 2010 integration.
+ +-->
+ <bean id="staffExchangeAdapter"
+ class="org.jasig.portlet.calendar.adapter.EWSJavaAPIExchange2010Adapter"
+ p:cache-ref="calendarCache" p:usernameAttribute="username" p:passwordAttribute="password" p:autodiscoverAttribute="mail"/>
+
+ <bean id="studentExchangeAdapter"
+ class="org.jasig.portlet.calendar.adapter.EWSJavaAPIExchange2010Adapter"
+ p:cache-ref="calendarCache" p:usernameAttribute="mail" p:passwordAttribute="password" p:autodiscoverAttribute="mail"/>
+
<!-- CalDAV adapter for calendars available via the CalDAV protocol -->
<bean id="calDavAdapter"
class="org.jasig.portlet.calendar.adapter.CalDavCalendarAdapter"
Index: pom.xml
===================================================================
--- pom.xml (revision 25508)
+++ pom.xml (working copy)
@@ -662,6 +662,32 @@
<artifactId>AjaxPortletSupport</artifactId>
</dependency>
+ <!-- Exchange / Live@EDU Dependencies -->
+ <dependency>
+ <groupId>microsoft</groupId>
+ <artifactId>EWSJavaAPI</artifactId>
+ <version>1.1.5</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-httpclient</groupId>
+ <artifactId>commons-httpclient</artifactId>
+ <version>3.1</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>1.4</version>
+ </dependency>
+ <dependency>
+ <groupId>jcifs</groupId>
+ <artifactId>jcifs</artifactId>
+ <version>1.3.15</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.3</version>
+ </dependency>
<!-- ===== Runtime Dependencies ================================== -->
<dependency>
Index: src/main/java/org/jasig/portlet/calendar/adapter/EWSJavaAPIExchange2010Adapter.java
===================================================================
--- src/main/java/org/jasig/portlet/calendar/adapter/EWSJavaAPIExchange2010Adapter.java (revision 0)
+++ src/main/java/org/jasig/portlet/calendar/adapter/EWSJavaAPIExchange2010Adapter.java (revision 0)
@@ -0,0 +1,238 @@
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work
+ * for additional information regarding copyright ownership.
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a
+ * copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jasig.portlet.calendar.adapter;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.portlet.PortletRequest;
+import javax.xml.datatype.DatatypeConfigurationException;
+
+import microsoft.exchange.webservices.data.Appointment;
+import microsoft.exchange.webservices.data.AutodiscoverLocalException;
+import microsoft.exchange.webservices.data.CalendarFolder;
+import microsoft.exchange.webservices.data.CalendarView;
+import microsoft.exchange.webservices.data.ExchangeCredentials;
+import microsoft.exchange.webservices.data.ExchangeService;
+import microsoft.exchange.webservices.data.FindItemsResults;
+import microsoft.exchange.webservices.data.IAutodiscoverRedirectionUrl;
+import microsoft.exchange.webservices.data.WebCredentials;
+import microsoft.exchange.webservices.data.WellKnownFolderName;
+import net.fortuna.ical4j.model.DateTime;
+import net.fortuna.ical4j.model.Period;
+import net.fortuna.ical4j.model.PropertyList;
+import net.fortuna.ical4j.model.property.DtEnd;
+import net.fortuna.ical4j.model.property.DtStart;
+import net.fortuna.ical4j.model.property.Location;
+import net.fortuna.ical4j.model.property.Summary;
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jasig.portlet.calendar.CalendarConfiguration;
+import org.jasig.portlet.calendar.CalendarEvent;
+import org.jasig.portlet.calendar.caching.DefaultCacheKeyGeneratorImpl;
+import org.jasig.portlet.calendar.caching.ICacheKeyGenerator;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.portlet.context.PortletRequestAttributes;
+
+/**
+ * Queries Exchange Web Services API for calendar events.
+ *
+ * @author Jen Bourey, jbou...@unicon.net
+ * @version $Revision$
+ */
+public class EWSJavaAPIExchange2010Adapter implements ICalendarAdapter {
+
+ protected final Log log = LogFactory.getLog(getClass());
+
+ public static final String EXCHANGE_URL_ATTRIBUTE = "exchangeUrl";
+
+
+ private Cache cache;
+ public void setCache(Cache cache) {
+ this.cache = cache;
+ }
+
+ private ICacheKeyGenerator cacheKeyGenerator = new DefaultCacheKeyGeneratorImpl();
+ public void setCacheKeyGenerator(ICacheKeyGenerator cacheKeyGenerator) {
+ this.cacheKeyGenerator = cacheKeyGenerator;
+ }
+
+ private String cacheKeyPrefix = "ewsjavaaexchange2010";
+ public void setCacheKeyPrefix(String cacheKeyPrefix) {
+ this.cacheKeyPrefix = cacheKeyPrefix;
+ }
+
+ private String usernameAttribute = "username";
+ public void setUsernameAttribute(String usernameAttribute) {
+ this.usernameAttribute = usernameAttribute;
+ }
+
+ private String passwordAttribute = "password";
+ public void setPasswordAttribute(String passwordAttribute) {
+ this.passwordAttribute = passwordAttribute;
+ }
+
+ private String autodiscoverAttribute = "mail";
+ public void setAutodiscoverAttribute(String autodiscoverAttribute) {
+ this.autodiscoverAttribute = autodiscoverAttribute;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.jasig.portlet.calendar.adapter.ICalendarAdapter#getEvents(org.jasig.portlet.calendar.CalendarConfiguration, net.fortuna.ical4j.model.Period, javax.portlet.PortletRequest)
+ */
+ public Set<CalendarEvent> getEvents(CalendarConfiguration calendarConfiguration,
+ Period period, PortletRequest request) throws CalendarException {
+ Set<CalendarEvent> events = Collections.emptySet();
+
+ // try to get the cached calendar
+
+ @SuppressWarnings("unchecked")
+ Map<String, String> userInfo = (Map<String, String>) request.getAttribute(PortletRequest.USER_INFO);
+ String username = userInfo.get(this.usernameAttribute);
+ String password = userInfo.get(this.passwordAttribute);
+ String autodiscoverValue = userInfo.get(this.autodiscoverAttribute);
+
+ String key = cacheKeyGenerator.getKey(calendarConfiguration, period, request, cacheKeyPrefix.concat(".").concat(username));
+ Element cachedElement = this.cache.get(key);
+ if (cachedElement == null) {
+ log.debug("Retreiving exchange events for account " + username);
+ events = retrieveExchangeEvents(calendarConfiguration, period, request, autodiscoverValue,username,password);
+ log.debug("Exchange adapter found " + events.size() + " events");
+ // save the CalendarEvents to the cache
+ cachedElement = new Element(key, events);
+ this.cache.put(cachedElement);
+ } else {
+ events = (Set<CalendarEvent>) cachedElement.getValue();
+ }
+
+ return events;
+ }
+
+ /**
+ * Retrieve a set of CalendarEvents from the Exchange server for the specified
+ * period and email address.
+ *
+ * @param calendar
+ * @param period
+ * @param emailAddress
+ * @return
+ * @throws CalendarException
+ */
+ public Set<CalendarEvent> retrieveExchangeEvents(CalendarConfiguration calendar, Period period, PortletRequest request, String autodiscoverValue, String username, String password) throws CalendarException {
+
+ if (log.isDebugEnabled()) {
+ StringBuilder buff = new StringBuilder();
+ buff.append("Period details: start=").append(period.getStart())
+ .append(", end=").append(period.getEnd());
+ log.debug(buff.toString());
+ }
+
+ Set<CalendarEvent> events = new HashSet<CalendarEvent>();
+
+ try {
+ ExchangeService service = new ExchangeService();
+ ExchangeCredentials exchangeCredentials = new WebCredentials(username,password);
+ service.setCredentials(exchangeCredentials);
+
+ final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
+ URI url = (URI) requestAttributes.getAttribute(EXCHANGE_URL_ATTRIBUTE, RequestAttributes.SCOPE_SESSION);
+ if(url == null) {
+ log.info("Exchange Url not availbale, using autodicsover");
+ url = autodiscoverUrl(autodiscoverValue, service, request);
+ }
+
+ service.setUrl(url);
+
+ CalendarFolder cf = CalendarFolder.bind(service, WellKnownFolderName.Calendar);
+ FindItemsResults<Appointment> findResults = cf.findAppointments(new CalendarView(period.getStart(), period.getEnd()));
+ for (Appointment appt : findResults.getItems()) {
+
+ //create a new UTC-based DateTime to represent the event start time
+ DateTime eventStart = new DateTime(appt.getStart());
+ DateTime eventEnd = new DateTime(appt.getEnd());
+
+ // create a property list representing the new event
+ PropertyList newprops = new PropertyList();
+ newprops.add(new DtStart(eventStart));
+ newprops.add(new DtEnd(eventEnd));
+ newprops.add(new Summary(appt.getSubject()));
+ if (StringUtils.isNotBlank(appt.getLocation())) {
+ newprops.add(new Location(appt.getLocation()));
+ }
+
+ CalendarEvent event = new CalendarEvent(calendar.getId(), newprops);
+ events.add(event);
+ }
+
+ } catch (DatatypeConfigurationException e) {
+ throw new CalendarException(e);
+ } catch (Exception e) {
+ throw new CalendarException(e);
+ }
+
+ return events;
+ }
+
+ public String getLink(CalendarConfiguration calendar, Period period,
+ PortletRequest request) throws CalendarLinkException {
+ // TODO Auto-generated method stub
+ return "";
+ }
+
+ private URI autodiscoverUrl(String autodiscoverValue, ExchangeService service, PortletRequest request) {
+
+ try {
+ service.autodiscoverUrl(autodiscoverValue,new IAutodiscoverRedirectionUrl() {
+ @Override
+ public boolean autodiscoverRedirectionUrlValidationCallback(String arg0)
+ throws AutodiscoverLocalException {
+ // TODO Check against a list of approved domains.
+ return true;
+ }
+ });
+
+ URI url = service.getUrl();
+
+ RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
+ if (requestAttributes == null) {
+ requestAttributes = new PortletRequestAttributes(request);
+ RequestContextHolder.setRequestAttributes(requestAttributes);
+ }
+ requestAttributes.setAttribute(EWSJavaAPIExchange2010Adapter.EXCHANGE_URL_ATTRIBUTE, url, RequestAttributes.SCOPE_SESSION);
+
+ return url;
+
+ } catch (Exception e) {
+ log.error("Cannot autodiscover url for "+autodiscoverValue);
+ }
+ return null;
+ }
+
+}
Property changes on: src/main/java/org/jasig/portlet/calendar/adapter/EWSJavaAPIExchange2010Adapter.java
___________________________________________________________________
Added: svn:eol-style
+ native
Added: svn:keywords
+ Date Revision Author HeadURL Id