// Copyright 2007 Google Inc.
//
// Licensed 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 com.google.enterprise.connector.afyd;
import com.google.gdata.client.appsforyourdomain.UserService;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.Link;
import com.google.gdata.data.appsforyourdomain.provisioning.UserFeed;
import com.google.gdata.data.appsforyourdomain.provisioning.UserEntry;
import com.google.gdata.util.ServiceException;
import com.google.gdata.util.NotModifiedException;
import com.google.gdata.util.AuthenticationException;
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.AbstractList;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Date;
import java.util.Collections;
import java.util.logging.Logger;
/**
* This class behaves like a basic List however it is really a caching layer
* in front of the user list fetchable using the Google Apps Provisioning API.
*
* The contents of this list are the plain text usernames (not email addresses)
* arranged by the natural ordering of Strings.
*
* Each call to this list that triggers a get() or size() will possibly cause
* a refetch from the back end service to occur. Once a refetch has occurred,
* it will not occur again for at least a period of the number of seconds
* specified by the "ttl" property.
*
* @author amsmith@google.com (Your Name Here)
*/
public class AfydBackedUserList extends AbstractList {
/** The logger for this class. */
private static final Logger LOGGER =
Logger.getLogger(AfydBackedUserList.class.getName());
private static final String USER_LIST_FEED_PATTERN =
"https://www.google.com/a/feeds/{domain}/user/2.0";
/** The time the real user list was last fetched */
private Date lastFetchDate;
/** The actual user list */
private List userList;
/** The domain this user list is for */
private String domain;
/** The service that will be used to fetch the user list */
private UserService service;
/** The number of seconds out-of-date the user list can be */
private int ttl = 0;
public void setTtl(int ttl) {
this.ttl = ttl;
}
public int getTtl() {
return ttl;
}
public AfydBackedUserList ( String domain,
String email,
String password,
UserService service)
throws AuthenticationException {
service.setUserCredentials(email, password);
this.domain = domain;
this.service = service;
}
/**
* Determines if refetch() should be called by examining lastFetchDate and the
* ttl fields.
*/
private void maybeRefetch() {
if (lastFetchDate == null) {
refetch();
} else {
long then = lastFetchDate.getTime();
long now = new Date().getTime();
if ((now - then) / 1000.0 > ttl ) {
refetch();
}
}
}
/**
* Fetches the actual user list from the injected UserService, updates the
* value of fetchTime
*
* The value of userList is never null after calling this method.
*/
private void refetch() {
Date newFetchDate = new Date();
DateTime lastFetchDateTime = null;
if (lastFetchDate != null) {
lastFetchDateTime = new DateTime(lastFetchDate);
}
String urlString = USER_LIST_FEED_PATTERN
.replaceAll("\\{domain\\}", domain);
URL feedUrl = null;
try {
feedUrl = new URL(urlString);
} catch (MalformedURLException murle) {
LOGGER.severe(murle.toString());
}
UserFeed feed = null;
try {
Link nextLink;
do {
UserFeed currentPage = (UserFeed) service.getFeed(
feedUrl, UserFeed.class, lastFetchDateTime);
if (feed == null) {
feed = new UserFeed();
}
feed.getEntries().addAll(currentPage.getEntries());
nextLink = currentPage.getLink(Link.Rel.NEXT, Link.Type.ATOM);
} while(nextLink != null);
} catch (IOException ioe) {
LOGGER.severe(ioe.toString());
} catch (NotModifiedException nme) {
LOGGER.info(nme.toString());
} catch (ServiceException se) {
LOGGER.severe(se.toString());
}
if (feed != null) {
List results = feed.getEntries();
userList = new ArrayList(results.size());
for (Iterator iter = results.iterator(); iter.hasNext(); ) {
userList.add( ((UserEntry) iter.next()).getLogin().getUserName() );
}
Collections.sort(userList);
}
if (userList == null)
userList = new ArrayList(0);
lastFetchDate = newFetchDate;
}
/**
* Gets an element from the cached user list.
*/
public Object get(int index) {
maybeRefetch();
return userList.get(index);
}
/**
* Gets the size from the cached user list.
*/
public int size() {
maybeRefetch();
return userList.size();
}
}