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

Reply via email to