Inital commit
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
This sample web application publishes events from Google Spreadsheets
|
||||
to Google Calendar and Google Base. A user visits this webapp,
|
||||
logs into their Google account using AuthSub and chooses the worksheet
|
||||
they wish to publish. The events stored in the spreadsheet are then
|
||||
transferred to a pre-configured Google Calendar and/or Google Base
|
||||
account. New events are added, while pre-existing events are updated.
|
||||
Please see the information below on how to configure credentials for
|
||||
Google Base and Google Calendar.
|
||||
|
||||
The following instructions assume some knowledge of building, deploying
|
||||
and running Java web applications.
|
||||
|
||||
In order to build and run this sample, there are a number of dependent
|
||||
libraries required:
|
||||
* GData Java Client Library:
|
||||
* URL:
|
||||
http://code.google.com/apis/gdata/
|
||||
* Definitions in build.properties:
|
||||
gdata_java_client_lib_client.jar
|
||||
gdata_java_client_lib_base.jar
|
||||
gdata_java_client_lib_calendar.jar
|
||||
gdata_java_client_lib_spreadsheet.jar
|
||||
* Sun's Java Activation Framework (JAF)
|
||||
* URL:
|
||||
http://java.sun.com/products/javabeans/jaf/downloads/index.html
|
||||
* Definitions in build.properties:
|
||||
activation.jar
|
||||
* Sun's Java Mail API
|
||||
* URL:
|
||||
http://java.sun.com/products/javamail/download.html
|
||||
* Definitions in build.properties:
|
||||
mail.jar
|
||||
* Sun's Servlet API library
|
||||
* URL:
|
||||
http://java.sun.com/products/servlet/download.html
|
||||
* Definitions in build.properties:
|
||||
servlet.jar
|
||||
* Jakarta Commons libraries
|
||||
* URL:
|
||||
http://jakarta.apache.org/commons/
|
||||
* Libraries:
|
||||
collections
|
||||
configuration
|
||||
lang
|
||||
* Definitions in build.properties:
|
||||
commons-collections.jar
|
||||
commons-configuration.jar
|
||||
commons-lang.jar
|
||||
* Jakarta Standard 1.1 Taglib
|
||||
* URL:
|
||||
http://jakarta.apache.org/site/downloads/downloads_taglibs-standard.cgi
|
||||
* Definitions in build.properties:
|
||||
jstl.jar
|
||||
standard.jar
|
||||
|
||||
There are also several tool/application dependencies:
|
||||
* Apache Ant
|
||||
* URL:
|
||||
http://ant.apache.org/
|
||||
* Servlet container such as Apache Tomcat or full app server such as JBoss
|
||||
* URLs:
|
||||
http://tomcat.apache.org/
|
||||
http://www.jboss.org/downloads/index
|
||||
|
||||
Before you begin, please do the following:
|
||||
1) Update build.properties to point to the correct location of the
|
||||
dependencies. By default, the appropriate jar files should be placed
|
||||
in /tmp/gdata_dep. Please see build.properties for a list of all
|
||||
jar files required.
|
||||
2) Update resources/EventPublisher.properties to include valid
|
||||
credentials for Google Base and Google Calendar, in addition to the URL
|
||||
for the Calendar to which you wish to publish events. Authentication to
|
||||
retrieve the Google Spreadsheets data is done via the AuthSub proxy
|
||||
authentication method
|
||||
3) Create a Google Spreadsheet which as the following columns. Note:
|
||||
the name of the columns can be different, as you will be given a chance
|
||||
to map the column names to the needed data in the web interface. However,
|
||||
columns dedicated to data of the defined types below are required.
|
||||
"Title" (text)
|
||||
"Description" (text)
|
||||
"Start Date" (Date in MM/DD/YYYY format)
|
||||
"End Date" (Date in MM/DD/YYYY format)
|
||||
"Web site" (text URL)
|
||||
"Location" (text)
|
||||
"Calendar URL" (text URL)
|
||||
"Base URL" (text URL)
|
||||
|
||||
|
||||
To build, run ant. A war file should be produced in the deploy directory.
|
||||
Deploy this file to your servlet container. Tomcat's default configuration,
|
||||
for example, will auto-deploy the war file if it is copied to <root>/webapps.
|
||||
|
||||
You should then be able to access this application at:
|
||||
http://hostname:port/EventPublisher
|
||||
|
||||
NOTE: This web application curently doesn't have much error feedback to the
|
||||
end-user visiting the application. Most exceptions are caught and logged
|
||||
to stderr, so please look at the server error logs if you are experiencing
|
||||
any problems with this application. In Tomcat, for instance, these errors
|
||||
would be logged to logs/catalina.out.
|
||||
@@ -0,0 +1,34 @@
|
||||
# External depdendencies
|
||||
#
|
||||
# The following relative paths point to locations inside the Java Client
|
||||
# Library, assuming the base directory is:
|
||||
# JAVA_CLIENT_LIB_INSTALL_DIR/java/mashups/EventPublisher/.
|
||||
# EDIT-THIS: If you move this project outside of the Java client library
|
||||
gdata_java_client_lib_client.jar=../../lib/gdata-client-1.0.jar
|
||||
gdata_java_client_lib_base.jar=../../lib/gdata-base-1.0.jar
|
||||
gdata_java_client_lib_calendar.jar=../../lib/gdata-calendar-1.0.jar
|
||||
gdata_java_client_lib_spreadsheet.jar=../../lib/gdata-spreadsheet-1.0.jar
|
||||
|
||||
# EDIT-THIS: # Point to the servlet jar in Sun's Servlet API library.
|
||||
servlet.jar=/tmp/gdata_dep/servlet-api-2.4.jar
|
||||
|
||||
# EDIT-THIS: Point to mail.jar lib in Sun's Java Mail API.
|
||||
mail.jar=/tmp/gdata_dep/mail.jar
|
||||
|
||||
# EDIT-THIS: If using version older than JDK 1.6,
|
||||
# Point to activation.jar in Sun's activation framework library.
|
||||
activation.jar=/tmp/gdata_dep/activation.jar
|
||||
|
||||
# EDIT-THIS: Point to the location of Jakarta Commons libraries
|
||||
commons-collections.jar=/tmp/gdata_dep/commons-collections-3.2.jar
|
||||
commons-configuration.jar=/tmp/gdata_dep/commons-configuration-1.4.jar
|
||||
commons-lang.jar=/tmp/gdata_dep/commons-lang-2.3.jar
|
||||
|
||||
# EDIT-THIS: Point to the location of JSTL API and implementation
|
||||
jstl.jar=/tmp/gdata_dep/jstl.jar
|
||||
standard.jar=/tmp/gdata_dep/standard.jar
|
||||
|
||||
# EDIT-THIS: Point to the location where .war files can be copied into your
|
||||
# servlet containers. For instance, tomcat has a <tomcatdir>/webapps
|
||||
# directory that's useful for this purpose
|
||||
#install_war_dir=
|
||||
@@ -0,0 +1,175 @@
|
||||
<project name="EventPublisher" default="all">
|
||||
<property environment="env"/>
|
||||
<property file="build.properties"/>
|
||||
<path id="classpath">
|
||||
<pathelement path="${env.classpath}"/>
|
||||
<fileset dir="./lib">
|
||||
<include name="**/*.jar"/>
|
||||
</fileset>
|
||||
<pathelement location="${servlet.jar}"/>
|
||||
</path>
|
||||
|
||||
<target name="clean">
|
||||
<delete dir="build"/>
|
||||
<delete dir="deploy"/>
|
||||
</target>
|
||||
|
||||
<target name="cleanbuild">
|
||||
<delete dir="build"/>
|
||||
</target>
|
||||
|
||||
<target name="checkdeps">
|
||||
<available file="${gdata_java_client_lib_client.jar}" property="has.gdata"/>
|
||||
<fail unless="has.gdata">missing GData client lib: ${gdata_java_client_lib_client.jar}/
|
||||
The example requires the GData Java Client Library.
|
||||
|
||||
You can download it from:
|
||||
http://code.google.com/apis/gdata/
|
||||
</fail>
|
||||
<available file="${servlet.jar}" property="has.servlet"/>
|
||||
<fail unless="has.servlet">missing jar file: ${servlet.jar}
|
||||
The example requires Sun's Servlet API (version 2.3 or 2.4), which
|
||||
is not included in this distribution.
|
||||
|
||||
You can download it from:
|
||||
http://java.sun.com/products/servlet/download.html
|
||||
Under SPECIFICATIONS/Java Servlet, download 'class files 2.3' from "2.3 - Final Release"
|
||||
</fail>
|
||||
<available file="${mail.jar}" property="has.mail"/>
|
||||
<fail unless="has.mail">missing jar file: ${mail.jar}
|
||||
The GData client requires Sun's javamail API (version 1.4), which
|
||||
is not included in this distribution.
|
||||
|
||||
You can download it from:
|
||||
http://java.sun.com/products/javamail/download.html
|
||||
|
||||
Then save it under:
|
||||
${mail.jar}
|
||||
</fail>
|
||||
<available file="${activation.jar}" property="has.activation"/>
|
||||
<fail unless="has.activation">missing jar file: ${activation.jar}
|
||||
The GData client requires Sun's Activation Framework 1.1, which
|
||||
is not included in this distribution.
|
||||
|
||||
You can download it from:
|
||||
http://java.sun.com/products/javabeans/jaf/downloads/index.html
|
||||
|
||||
Then save it under:
|
||||
${activation.jar}
|
||||
</fail>
|
||||
<available file="${commons-collections.jar}" property="has.commons-collections"/>
|
||||
<fail unless="has.commons-collections">missing jar file: ${commons-collections.jar}
|
||||
The EventPublisher sample requires some Jakarta Commons components, which are
|
||||
not included in this distribution.
|
||||
|
||||
You can download it from:
|
||||
http://jakarta.apache.org/commons/
|
||||
|
||||
Then save it under:
|
||||
${commons-collections.jar}
|
||||
</fail>
|
||||
<available file="${commons-configuration.jar}" property="has.commons-configuration"/>
|
||||
<fail unless="has.commons-configuration">missing jar file: ${commons-configuration.jar}
|
||||
The EventPublisher sample requires some Jakarta Commons components, which are
|
||||
not included in this distribution.
|
||||
|
||||
You can download it from:
|
||||
http://jakarta.apache.org/commons/
|
||||
|
||||
Then save it under:
|
||||
${commons-configuration.jar}
|
||||
</fail>
|
||||
<available file="${commons-lang.jar}" property="has.commons-lang"/>
|
||||
<fail unless="has.commons-lang">missing jar file: ${commons-lang.jar}
|
||||
The EventPublisher sample requires some Jakarta Commons components, which are
|
||||
not included in this distribution.
|
||||
|
||||
You can download it from:
|
||||
http://jakarta.apache.org/commons/
|
||||
|
||||
Then save it under:
|
||||
${commons-lang.jar}
|
||||
</fail>
|
||||
<available file="${jstl.jar}" property="has.jstl"/>
|
||||
<fail unless="has.jstl">missing jar file: ${jstl.jar}
|
||||
The EventPublisher sample requires the Jakarta Standard 1.1 Taglib's
|
||||
API and implementation jars, which are not included in this distribution.
|
||||
|
||||
You can download it from:
|
||||
http://jakarta.apache.org/site/downloads/downloads_taglibs-standard.cgi
|
||||
|
||||
Then save it under:
|
||||
${jstl.jar}
|
||||
</fail>
|
||||
<available file="${standard.jar}" property="has.standard"/>
|
||||
<fail unless="has.standard">missing jar file: ${standard.jar}
|
||||
The EventPublisher sample requires the Jakarta Standard 1.1 Taglib's
|
||||
API and implementation jars, which are not included in this distribution.
|
||||
|
||||
You can download it from:
|
||||
http://jakarta.apache.org/site/downloads/downloads_taglibs-standard.cgi
|
||||
|
||||
Then save it under:
|
||||
${standard.jar}
|
||||
</fail>
|
||||
</target>
|
||||
|
||||
<target name="copydeps" depends="checkdeps">
|
||||
<mkdir dir="lib"/>
|
||||
<copy todir="lib">
|
||||
<fileset file="${gdata_java_client_lib_client.jar}"/>
|
||||
<fileset file="${gdata_java_client_lib_spreadsheet.jar}"/>
|
||||
<fileset file="${gdata_java_client_lib_calendar.jar}"/>
|
||||
<fileset file="${gdata_java_client_lib_base.jar}"/>
|
||||
<fileset file="${activation.jar}"/>
|
||||
<fileset file="${mail.jar}"/>
|
||||
<fileset file="${commons-collections.jar}"/>
|
||||
<fileset file="${commons-configuration.jar}"/>
|
||||
<fileset file="${commons-lang.jar}"/>
|
||||
<fileset file="${jstl.jar}"/>
|
||||
<fileset file="${standard.jar}"/>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="build" depends="copydeps">
|
||||
<mkdir dir="build"/>
|
||||
<javac classpathref="classpath" srcdir="src" destdir="build">
|
||||
<compilerarg value="-Xlint:unchecked"/>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="deploy" depends="build">
|
||||
<mkdir dir="deploy"/>
|
||||
<mkdir dir="deploy/content"/>
|
||||
<mkdir dir="deploy/content/WEB-INF"/>
|
||||
<mkdir dir="deploy/content/WEB-INF/lib"/>
|
||||
<copy todir="deploy/content/WEB-INF">
|
||||
<fileset file="resources/web.xml"/>
|
||||
</copy>
|
||||
<copy todir="deploy/content/WEB-INF/lib">
|
||||
<fileset dir="lib/"/>
|
||||
</copy>
|
||||
<copy todir="deploy/content/WEB-INF/classes">
|
||||
<fileset dir="build/"/>
|
||||
<fileset file="resources/*.properties"/>
|
||||
</copy>
|
||||
<copy todir="deploy/content/WEB-INF/jsp">
|
||||
<fileset dir="jsp/"/>
|
||||
</copy>
|
||||
<copy todir="deploy/content/">
|
||||
<fileset dir="resources/web/"/>
|
||||
</copy>
|
||||
<jar destfile="deploy/EventPublisher.war" basedir="deploy/content/"/>
|
||||
</target>
|
||||
|
||||
<target name="install" depends="deploy">
|
||||
<available file="${install_war_dir}" type="dir" property="has.installdir"/>
|
||||
<fail unless="has.installdir">Installation dir 'install_war_dir'
|
||||
property not defined. No install was made</fail>
|
||||
<copy todir="${install_war_dir}">
|
||||
<fileset file="deploy/EventPublisher.war"/>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="all" depends="clean,checkdeps,copydeps,build,deploy,cleanbuild"/>
|
||||
</project>
|
||||
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" ?>
|
||||
<%@ page language="java" contentType="text/html" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Column List</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/app.css" />
|
||||
</head>
|
||||
<body>
|
||||
<form method="post" action="?action=listEvents">
|
||||
<h1>Event Publisher</h1>
|
||||
<h2>Please map needed data to the appropriate columns:</h2>
|
||||
<input type="hidden" name="action" value="listEvents" />
|
||||
<ul>
|
||||
<li>
|
||||
Title:
|
||||
<select name="fdTitle">
|
||||
<c:forEach var="column" items="${columnList}">
|
||||
<option value="<c:out value='${column}' />">
|
||||
<c:out value='${column}' />
|
||||
</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</li>
|
||||
<li>
|
||||
Description:
|
||||
<select name="fdDescription">
|
||||
<c:forEach var="column" items="${columnList}">
|
||||
<option value="<c:out value='${column}' />">
|
||||
<c:out value='${column}' />
|
||||
</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</li>
|
||||
<li>
|
||||
Start Date:
|
||||
<select name="fdStartDate">
|
||||
<c:forEach var="column" items="${columnList}">
|
||||
<option value="<c:out value='${column}' />">
|
||||
<c:out value='${column}' />
|
||||
</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</li>
|
||||
<li>
|
||||
End Date:
|
||||
<select name="fdEndDate">
|
||||
<c:forEach var="column" items="${columnList}">
|
||||
<option value="<c:out value='${column}' />">
|
||||
<c:out value='${column}' />
|
||||
</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</li>
|
||||
<li>
|
||||
Location:
|
||||
<select name="fdLocation">
|
||||
<c:forEach var="column" items="${columnList}">
|
||||
<option value="<c:out value='${column}' />">
|
||||
<c:out value='${column}' /><br />
|
||||
</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</li>
|
||||
<li>
|
||||
Web Site:
|
||||
<select name="fdWebSite">
|
||||
<c:forEach var="column" items="${columnList}">
|
||||
<option value="<c:out value='${column}' />">
|
||||
<c:out value='${column}' /><br />
|
||||
</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</li>
|
||||
<li>
|
||||
Calendar Event Url:
|
||||
<select name="fdCalendarUrl">
|
||||
<c:forEach var="column" items="${columnList}">
|
||||
<option value="<c:out value='${column}' />">
|
||||
<c:out value='${column}' /><br />
|
||||
</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</li>
|
||||
<li>
|
||||
Base Event Url:
|
||||
<select name="fdBaseUrl">
|
||||
<c:forEach var="column" items="${columnList}">
|
||||
<option value="<c:out value='${column}' />">
|
||||
<c:out value='${column}' /><br />
|
||||
</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</li>
|
||||
</ul>
|
||||
<input type="submit" value="Publish Events" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" ?>
|
||||
<%@ page language="java" contentType="text/html" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Events</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/app.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Event Publisher</h1>
|
||||
<h2>Events to be published:</h2>
|
||||
<ul>
|
||||
<c:forEach var="event" items="${events}">
|
||||
<li><b><c:out value="${event.title}"/></b>
|
||||
<ul>
|
||||
<li>Description: <c:out value="${event.description}"/></li>
|
||||
<li>Start Date: <fmt:formatDate value="${event.startDate}" dateStyle="full"/></li>
|
||||
<li>End Date: <fmt:formatDate value="${event.endDate}" dateStyle="full"/></li>
|
||||
</ul>
|
||||
</li>
|
||||
</c:forEach>
|
||||
</ul>
|
||||
<form method="post" action="?action=publish">
|
||||
<h2>Publish these events to the following targets:</h2>
|
||||
<ul>
|
||||
<li><input type="checkbox" name="calendar" value="checked" /> Calendar</li>
|
||||
<li><input type="checkbox" name="base" value="checked" /> Base</li>
|
||||
</ul>
|
||||
<input type="hidden" name="action" value="publish" />
|
||||
<input type="submit" value="Publish" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" ?>
|
||||
<%@ page language="java" contentType="text/html" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Welcome to the Event Publisher</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/app.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Event Publisher</h1>
|
||||
<p>
|
||||
You can publish events to a Google Calendar and/or to Google Base from
|
||||
a private spreadsheet on Google Spreadsheets.
|
||||
</p>
|
||||
<h2>Publish from a private spreadsheet</h2>
|
||||
<p>
|
||||
To access the private Google Spreadsheet to use for publishing, please
|
||||
<a href="<c:out value="${ssAuthUrl}" />">authenticate</a> to your Google
|
||||
Account
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" ?>
|
||||
<%@ page language="java" contentType="text/html" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Publishing Results</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/app.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Event Publisher</h1>
|
||||
<h2>Publishing successful:</h2>
|
||||
<ul>
|
||||
<li><a href="?action=listEvents">Publish again</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" ?>
|
||||
<%@ page language="java" contentType="text/html" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Spreadsheet List</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/app.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Event Publisher</h1>
|
||||
<h2>Spreadsheets available:</h2>
|
||||
<ul>
|
||||
<c:forEach var="ss" items="${ssList}">
|
||||
<li><a href="?action=outputWsList&wsFeed=<c:out value='${ss["wsFeed"]}' />">
|
||||
<c:out value='${ss["title"]}' />
|
||||
</a></li>
|
||||
</c:forEach>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" ?>
|
||||
<%@ page language="java" contentType="text/html" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Worksheet List</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/app.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Event Publisher</h1>
|
||||
<h2>Worksheets available:</h2>
|
||||
<ul>
|
||||
<c:forEach var="ws" items="${wsList}">
|
||||
<li><a href="?action=outputColumnList&cellFeed=<c:out value='${ws["cellFeed"]}' />"><c:out value='${ws["title"]}' /></a> </li>
|
||||
</c:forEach>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
# EDIT-THIS: Credentials for Google Calendar
|
||||
calendar.username=example@example.com
|
||||
calendar.password=password
|
||||
calendar.url=http://www.google.com/calendar/feeds/example%40group.calendar.google.com/private/full
|
||||
|
||||
# EDIT-THIS: Credentials for Google Calendar
|
||||
# Credentials for Google Base
|
||||
gbase.username=example@example.com
|
||||
gbase.password=password
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app id="EventPublisher" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
|
||||
<display-name>EventPublisher</display-name>
|
||||
<servlet>
|
||||
<description></description>
|
||||
<display-name>EventPublisherServlet</display-name>
|
||||
<servlet-name>EventPublisherServlet</servlet-name>
|
||||
<servlet-class>
|
||||
mashups.eventpub.EventPublisherServlet
|
||||
</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>EventPublisherServlet</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>default</servlet-name>
|
||||
<url-pattern>*.css</url-pattern>
|
||||
</servlet-mapping>
|
||||
</web-app>
|
||||
@@ -0,0 +1,241 @@
|
||||
body {
|
||||
font-family: arial, sans-serif;
|
||||
background-color:#fff;
|
||||
font-size: small;
|
||||
margin: 24px 8px 8px;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
/* ########## HYPERLINKS ########## */
|
||||
|
||||
a{
|
||||
color: #0000cc;
|
||||
}
|
||||
|
||||
a:active {
|
||||
color: #cc0000;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #551a8b;
|
||||
}
|
||||
|
||||
/* ########## END HYPERLINKS ########## */
|
||||
|
||||
/* ########## FONT FORMATS ########## */
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
font-weight:bold;
|
||||
margin-bottom:0;
|
||||
}
|
||||
|
||||
h2, h3, h4, h5 {
|
||||
margin-left:25px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size:130%;
|
||||
margin:2em 0 0 10px;
|
||||
padding:0 3px 0 3px;
|
||||
border-top: 1px solid;
|
||||
background-color: #e5ecf9;
|
||||
border-color: #3366CC;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size:120%;
|
||||
margin-top:1.5em;
|
||||
border-bottom: 1px solid;
|
||||
border-color: #3366CC;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size:110%;
|
||||
margin-top:.7em;
|
||||
position:relative;
|
||||
left:0;
|
||||
top:.7em;
|
||||
z-index:5; /*to avoid falling behind other elements due to lowered position*/
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-top:.5em;
|
||||
font-size:100%;
|
||||
font-weight:bold;
|
||||
position:relative;
|
||||
left:0;
|
||||
top:.8em;
|
||||
z-index:5; /*to avoid falling behind other elements due to lowered position*/
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin-top:.4em;
|
||||
font-size:100%;
|
||||
font-weight:100;
|
||||
font-style:italic;
|
||||
text-decoration:underline;
|
||||
position:relative;
|
||||
left:0;
|
||||
top:.8em;
|
||||
z-index:5; /*to avoid falling behind other elements due to lowered position*/
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 1em 0 0 25px;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
ol, ul, dl{
|
||||
padding-top:.5em;
|
||||
margin-top:0;
|
||||
margin-bottom:0;
|
||||
}
|
||||
|
||||
ol li ol, ul li ul{
|
||||
padding:.1em 0 0 0;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
li{
|
||||
margin: .4em 0 0 1.5em;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
dt{
|
||||
font-weight:bold;
|
||||
margin:.75em 0 0 25px;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
dd{
|
||||
margin: .4em 0 0 4em;
|
||||
padding:0;
|
||||
font-weight:normal;
|
||||
}
|
||||
|
||||
ul li p, ol li p{
|
||||
margin: 0 0 0 20px;
|
||||
padding:.4em 0 0 0;
|
||||
font-weight:normal;
|
||||
}
|
||||
|
||||
.listhead li{
|
||||
font-weight:bold;
|
||||
margin:.75em 0 0 1.5em;
|
||||
}
|
||||
|
||||
.listhead li p{
|
||||
font-weight:normal;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ol.alpha{list-style:lower-alpha;}
|
||||
ol.alphacap{list-style:upper-alpha;}
|
||||
ol.roman{list-style:lower-roman;}
|
||||
ol.romancap{list-style:upper-roman;}
|
||||
|
||||
|
||||
code{
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.code li{
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 100%;
|
||||
margin-top:.75em;
|
||||
}
|
||||
|
||||
.code li p{
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ul li p.note, ul li p.warning, ul li p.caution,
|
||||
ol li p.note, ol li p.warning, ol li p.caution{
|
||||
margin: .8em 0 0 0;
|
||||
padding:.2em .5em .2em .9em;
|
||||
background-color: #efefef;
|
||||
border-top: #ccc 1px solid;
|
||||
}
|
||||
|
||||
form {
|
||||
padding:0;
|
||||
margin:2em 0 0 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #eee;
|
||||
border: 1px solid #bbb;
|
||||
color: #000000;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 100%;
|
||||
margin: 1em 0 0 25px;
|
||||
padding: .9em;
|
||||
text-align:left;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
li pre{
|
||||
margin: 1em 0 0 0;
|
||||
padding: .9em;
|
||||
}
|
||||
|
||||
|
||||
blockquote {
|
||||
text-align:justify;
|
||||
background: url("quote.gif") no-repeat;
|
||||
background-position: 0% 0%;
|
||||
padding:10px 20px 5px 20px;
|
||||
margin:1em 90px 0 70px;
|
||||
}
|
||||
|
||||
/* ########## END FONT FORMATS ########## */
|
||||
|
||||
/* ########## TABLES ########## */
|
||||
|
||||
table {
|
||||
border: 1px solid;
|
||||
border-color: #3366CC;
|
||||
border-spacing:0;
|
||||
margin: 1em 0 0 26px;
|
||||
border-collapse:collapse;
|
||||
clear:right;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight:bold;
|
||||
text-align:left;
|
||||
margin-left:3%;
|
||||
border: 1px solid #3366CC;
|
||||
text-align: left;
|
||||
padding: 6px 6px 6px 12px;
|
||||
background-color: #e5ecf9;
|
||||
}
|
||||
|
||||
td {
|
||||
border: 1px solid #3366CC;
|
||||
background: #fff;
|
||||
text-align:left;
|
||||
margin-left:3%;
|
||||
padding: 6px 6px 6px 12px;
|
||||
vertical-align:top;
|
||||
}
|
||||
|
||||
td.alt {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
/* ########## END TABLES ########## */
|
||||
|
||||
/* ########## MISCELLANEOUS ########## */
|
||||
|
||||
hr{
|
||||
border: 1px solid;
|
||||
border-color: #3366CC;
|
||||
margin: 20px 10px 20px 10px;
|
||||
}
|
||||
|
||||
/* ########## END MISCELLANEOUS ########## */
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Copyright (c) 2008 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 mashups.eventpub;
|
||||
|
||||
/**
|
||||
* Authentication exception class for the EventPublisher
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class EPAuthenticationException extends Exception {
|
||||
|
||||
public static final long serialVersionUID = 1L;
|
||||
|
||||
public EPAuthenticationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public EPAuthenticationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public EPAuthenticationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/* Copyright (c) 2008 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 mashups.eventpub;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Date;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
/**
|
||||
* Bean object to store event information used for synchronization
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class Event implements Serializable {
|
||||
|
||||
public static final long serialVersionUID = 1L;
|
||||
|
||||
private String title;
|
||||
private String description;
|
||||
private String website;
|
||||
|
||||
private Date startDate;
|
||||
private Date endDate;
|
||||
private URL baseUrl = null;
|
||||
private URL calendarUrl = null;
|
||||
private URL ssEditUrl = null;
|
||||
public int ssRow = -1;
|
||||
|
||||
private static final Pattern DATE_PATTERN =
|
||||
Pattern.compile("(\\d\\d?)/(\\d\\d?)/(\\d\\d\\d\\d)");
|
||||
|
||||
/**
|
||||
* Constructs a new Event instance with the specified properties
|
||||
*
|
||||
* @param title The title of the event
|
||||
* @param description The descriptin of the event
|
||||
* @param website The website representing the event
|
||||
* @param startDate The start date for the event in MM/DD/YYYY format
|
||||
* @param endDate The end date for the event in MM/DD/YYYY format
|
||||
* @param calendarUrl The edit URL for this event in Google Calendar
|
||||
* @param baseUrl The edit URL for this event in Google Base
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
public Event(String title, String description, String website,
|
||||
String startDate, String endDate, String calendarUrl, String baseUrl)
|
||||
throws MalformedURLException {
|
||||
this.setTitle(title);
|
||||
this.setDescription(description);
|
||||
this.setWebsite(website);
|
||||
this.setStartDate(startDate);
|
||||
this.setEndDate(endDate);
|
||||
this.setCalendarUrl(calendarUrl);
|
||||
this.setBaseUrl(baseUrl);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper method to convert a data in MM/DD/YYYY format into
|
||||
* a <code>java.util.Date</code>
|
||||
*
|
||||
* @param dateString The date string in MM/DD/YYYY format
|
||||
* @return The <code>java.util.Date</code> representing the string
|
||||
*/
|
||||
private Date stringToDate(String dateString) {
|
||||
Matcher m = DATE_PATTERN.matcher(dateString);
|
||||
Calendar date = new GregorianCalendar();
|
||||
if (!m.matches()) {
|
||||
throw new NumberFormatException("Invalid date format.");
|
||||
}
|
||||
date.set(Integer.valueOf(m.group(3)),
|
||||
Integer.valueOf(m.group(1)) - 1,
|
||||
Integer.valueOf(m.group(2)),
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
return date.getTime();
|
||||
}
|
||||
|
||||
public Date getStartDate() {
|
||||
return startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start date for this event. The data is stored as a
|
||||
* <code>java.util.date</code>, so this method calls a helper to
|
||||
* parse the date string.
|
||||
*
|
||||
* @param startDate The end date for the event in MM/DD/YYYY format
|
||||
*/
|
||||
public void setStartDate(String startDate) {
|
||||
this.startDate = stringToDate(startDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end date for this event. The data is stored as a
|
||||
* <code>java.util.date</code>, so this method calls a helper to
|
||||
* parse the date string.
|
||||
*
|
||||
* @param endDate The end date for the event in MM/DD/YYYY format
|
||||
*/
|
||||
public void setEndDate(String endDate) {
|
||||
this.endDate = stringToDate(endDate);
|
||||
}
|
||||
|
||||
public Date getEndDate() {
|
||||
return endDate;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setWebsite(String website) {
|
||||
this.website = website;
|
||||
}
|
||||
|
||||
public String getWebsite() {
|
||||
return website;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Calendar edit URL for this event
|
||||
*
|
||||
* @param calendarUrl The edit URL for this event
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
public void setCalendarUrl(String calendarUrl) throws MalformedURLException {
|
||||
if (calendarUrl != null && ! calendarUrl.trim().equals("")) {
|
||||
this.calendarUrl = new URL(calendarUrl);
|
||||
}
|
||||
}
|
||||
|
||||
public URL getCalendarUrl() {
|
||||
return this.calendarUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Base edit URL for this event
|
||||
*
|
||||
* @param baseUrl The edit URL for this event
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
public void setBaseUrl(String baseUrl) throws MalformedURLException {
|
||||
if (baseUrl != null && ! baseUrl.trim().equals("")) {
|
||||
this.baseUrl = new URL(baseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
public URL getBaseUrl() {
|
||||
return this.baseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Spreadsheets edit URL for this event
|
||||
*
|
||||
* @param baseUrl The edit URL for this event
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
public void setSsEditUrl(String ssEditUrl) throws MalformedURLException {
|
||||
if (ssEditUrl != null && ! ssEditUrl.trim().equals("")) {
|
||||
this.ssEditUrl = new URL(ssEditUrl);
|
||||
}
|
||||
}
|
||||
|
||||
public URL getSsEditUrl() {
|
||||
return this.ssEditUrl;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,737 @@
|
||||
/* Copyright (c) 2008 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 mashups.eventpub;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Date;
|
||||
|
||||
import com.google.api.gbase.client.DateTimeRange;
|
||||
import com.google.api.gbase.client.FeedURLFactory;
|
||||
import com.google.api.gbase.client.GoogleBaseAttributesExtension;
|
||||
import com.google.api.gbase.client.GoogleBaseEntry;
|
||||
import com.google.api.gbase.client.GoogleBaseService;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
import com.google.gdata.client.spreadsheet.SpreadsheetService;
|
||||
import com.google.gdata.client.calendar.CalendarService;
|
||||
import com.google.gdata.client.http.AuthSubUtil;
|
||||
import com.google.gdata.data.DateTime;
|
||||
import com.google.gdata.data.PlainTextConstruct;
|
||||
import com.google.gdata.data.calendar.CalendarEventEntry;
|
||||
import com.google.gdata.data.extensions.When;
|
||||
import com.google.gdata.data.spreadsheet.CellEntry;
|
||||
import com.google.gdata.data.spreadsheet.CellFeed;
|
||||
import com.google.gdata.data.spreadsheet.CustomElementCollection;
|
||||
import com.google.gdata.data.spreadsheet.ListEntry;
|
||||
import com.google.gdata.data.spreadsheet.ListFeed;
|
||||
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
|
||||
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
|
||||
import com.google.gdata.data.spreadsheet.WorksheetEntry;
|
||||
import com.google.gdata.data.spreadsheet.WorksheetFeed;
|
||||
import com.google.gdata.util.httputil.FastURLEncoder;
|
||||
|
||||
|
||||
/**
|
||||
* Publisher for pushing events from Spreadsheets to Calendar and Base
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class EventPublisher {
|
||||
|
||||
/**
|
||||
* The URL for the Spreadsheets meta feed, containing entries representing
|
||||
* individual spreadsheets accessible to the authenticated user
|
||||
*/
|
||||
private static final String SPREADSHEETS_META_FEED =
|
||||
"http://spreadsheets.google.com/feeds/spreadsheets/private/full";
|
||||
|
||||
/**
|
||||
* The URL for the Spreadsheets feed scope, as passed to the AuthSub
|
||||
* service in the AuthSubRequest URL scope parameter.
|
||||
*/
|
||||
private static final String SPREADSHEETS_SCOPE =
|
||||
"http://spreadsheets.google.com/feeds/";
|
||||
|
||||
/**
|
||||
* The app identity string used for the 'source' required by the
|
||||
* ClientLogin service. The GData Java Client Library also sends this value
|
||||
* to the GData services as part of the <code>User-Agent</code> HTTP header.
|
||||
*/
|
||||
private static final String APP_IDENTITY = "google-mashups-EventPublisher";
|
||||
|
||||
/**
|
||||
* The authenticated CalendarService object used for publishing
|
||||
*/
|
||||
private CalendarService calService = null;
|
||||
|
||||
/**
|
||||
* The authenticated CalendarService object used for publishing
|
||||
*/
|
||||
private GoogleBaseService baseService = null;
|
||||
|
||||
/**
|
||||
* The authenticated SpreadsheetService object used for retrieving events
|
||||
*/
|
||||
private SpreadsheetService ssService = null;
|
||||
|
||||
/**
|
||||
* URL representing the Google Spreadsheets list feed from which the events
|
||||
* are published. Note, this feed is not the meta feed of spreadsheets. It
|
||||
* is the list feed containing entries representing each row of the
|
||||
* spreadsheet.
|
||||
*/
|
||||
private URL ssUrl = null;
|
||||
|
||||
/* Spreadsheets credentials for authentication */
|
||||
private String ssUsername = null;
|
||||
private String ssPassword = null;
|
||||
private String ssAuthSubToken = null;
|
||||
|
||||
/**
|
||||
* URL representing the Google Calendar feed to which events can be
|
||||
* published
|
||||
*/
|
||||
private URL calUrl = null;
|
||||
|
||||
/* Calendar credentials for authentication */
|
||||
private String calUsername = null;
|
||||
private String calPassword = null;
|
||||
|
||||
/* Google Base credentials for authentication */
|
||||
private String baseUsername = null;
|
||||
private String basePassword = null;
|
||||
|
||||
/**
|
||||
* Contains the mapping between field names used by the
|
||||
* spreadsheet and those required in Calendar and Base
|
||||
*/
|
||||
private SpreadsheetCustomFieldMap fieldMap = null;
|
||||
|
||||
public void setFieldMap(SpreadsheetCustomFieldMap fieldMap) {
|
||||
this.fieldMap = fieldMap;
|
||||
}
|
||||
|
||||
public void setSsUrl(String ssUrlText) throws MalformedURLException {
|
||||
this.ssUrl = new URL(ssUrlText);
|
||||
}
|
||||
|
||||
public void setSsUsernamePassword(String username, String password) {
|
||||
this.ssUsername = username;
|
||||
this.ssPassword = password;
|
||||
}
|
||||
|
||||
public void setCalUsernamePassword(String username, String password) {
|
||||
this.calUsername = username;
|
||||
this.calPassword = password;
|
||||
}
|
||||
|
||||
public void setBaseUsernamePassword(String username, String password) {
|
||||
this.baseUsername = username;
|
||||
this.basePassword = password;
|
||||
}
|
||||
|
||||
public void setCalUrl(String calUrl) throws MalformedURLException {
|
||||
this.calUrl = new URL(calUrl);
|
||||
}
|
||||
|
||||
public String getSsAuthSubToken() {
|
||||
return this.ssAuthSubToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the AuthSub token used for Google Spreadsheets data API auth.
|
||||
* The method can, optionally, exchange the token for a session token
|
||||
* should a session token be desired.
|
||||
*
|
||||
* @param token The AuthSub token (either a a single-use or session token)
|
||||
* @param exchange True if the token supplied is a single-use token and
|
||||
* should be exchanged for a session token.
|
||||
* @throws EPAuthenticationException
|
||||
*/
|
||||
public void setSsAuthSubToken(String token, boolean exchange)
|
||||
throws EPAuthenticationException {
|
||||
if (exchange) {
|
||||
try {
|
||||
this.ssAuthSubToken = AuthSubUtil.exchangeForSessionToken(token, null);
|
||||
} catch (com.google.gdata.util.AuthenticationException authEx) {
|
||||
throw new
|
||||
EPAuthenticationException(
|
||||
"Single use token could not be exchanged", authEx);
|
||||
} catch (IOException ex) {
|
||||
throw new
|
||||
EPAuthenticationException(
|
||||
"Single use token could not be exchanged", ex);
|
||||
} catch (GeneralSecurityException ex) {
|
||||
throw new
|
||||
EPAuthenticationException(
|
||||
"Single use token could not be exchanged", ex);
|
||||
}
|
||||
} else {
|
||||
this.ssAuthSubToken = token;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves events from the spreadsheet and creates a <code>List</code>
|
||||
* of <code>Event</code> instances representing the events.
|
||||
*
|
||||
* @throws EPAuthenticatonException
|
||||
*/
|
||||
public List<Event> getEventsFromSpreadsheet()
|
||||
throws EPAuthenticationException {
|
||||
List<Event> eventList = new LinkedList<Event>();
|
||||
List<ListEntry> ssEntryList = getSsEntryListHelper();
|
||||
// counter used to store row number in event
|
||||
int i = 1;
|
||||
for (ListEntry ssRow : ssEntryList) {
|
||||
i++;
|
||||
// CustomElementCollection represents elements in the gsx namespace
|
||||
CustomElementCollection elements = ssRow.getCustomElements();
|
||||
try {
|
||||
Event e = new Event(
|
||||
elements.getValue(fieldMap.getTitleColumn()),
|
||||
elements.getValue(fieldMap.getDescriptionColumn()),
|
||||
elements.getValue(fieldMap.getWebsiteColumn()),
|
||||
elements.getValue(fieldMap.getStartColumn()),
|
||||
elements.getValue(fieldMap.getEndColumn()),
|
||||
elements.getValue(fieldMap.getCalendarUrlColumn()),
|
||||
elements.getValue(fieldMap.getBaseUrlColumn()));
|
||||
e.ssRow = i;
|
||||
e.setSsEditUrl(ssRow.getEditLink().getHref());
|
||||
eventList.add(e);
|
||||
} catch (MalformedURLException urlEx) {
|
||||
System.err.println("Could not read event titled '" +
|
||||
elements.getValue(fieldMap.getTitleColumn()) +
|
||||
"' due to a bad URL for the Calendar or Base URL");
|
||||
}
|
||||
}
|
||||
return eventList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of Spreadsheets for the authenticated user
|
||||
*
|
||||
* @return Returns a list of HashMaps with meta-data about each spreadsheet.
|
||||
* @throws EPAuthenticationException
|
||||
*/
|
||||
public List<HashMap> getSsList()
|
||||
throws EPAuthenticationException {
|
||||
List<HashMap> returnList = new LinkedList<HashMap>();
|
||||
List<SpreadsheetEntry> ssList = getSsListHelper();
|
||||
for (SpreadsheetEntry ssEntry : ssList) {
|
||||
HashMap<String, String> hm = new HashMap<String, String>();
|
||||
hm.put("title", ssEntry.getTitle().getPlainText());
|
||||
try {
|
||||
hm.put("wsFeed", FastURLEncoder.encode(
|
||||
ssEntry.getWorksheetFeedUrl().toString(),
|
||||
"UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
System.err.println("Encoding error: " + e.getMessage());
|
||||
}
|
||||
returnList.add(hm);
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of Worksheets for the specified
|
||||
* spreadsheet
|
||||
*
|
||||
* @param wsFeedUrl The URL for the feed containing the list of worksheets
|
||||
* @return A <code>List</code> of <code>HashMap</code> meta data about each
|
||||
* worksheet
|
||||
* @throws EPAuthenticationException
|
||||
*/
|
||||
public List<HashMap> getWsList(String wsFeedUrl)
|
||||
throws EPAuthenticationException {
|
||||
List<HashMap> returnList = new LinkedList<HashMap>();
|
||||
List<WorksheetEntry> wsList = getWsListHelper(wsFeedUrl);
|
||||
for (WorksheetEntry wsEntry : wsList) {
|
||||
HashMap<String, String> hm = new HashMap<String, String>();
|
||||
hm.put("title", wsEntry.getTitle().getPlainText());
|
||||
try {
|
||||
hm.put("cellFeed", FastURLEncoder.encode(
|
||||
wsEntry.getCellFeedUrl().toString(),
|
||||
"UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
System.err.println("Encoding error: " + e.getMessage());
|
||||
}
|
||||
returnList.add(hm);
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL for redirecting users to in order to authenticate to
|
||||
* the AuthSub service for access to a Google Spreadsheets account via
|
||||
* the API.
|
||||
*
|
||||
* @param nextUrl The URL to which the authenticated user will be redirected
|
||||
* to after successfully authenticating
|
||||
*/
|
||||
public static String getSsAuthSubUrl(String nextUrl) {
|
||||
// requests a single-use token which can be upgraded to a session token
|
||||
// and is not set with the AuthSub secure flag
|
||||
return AuthSubUtil.getRequestUrl(nextUrl,
|
||||
SPREADSHEETS_SCOPE,
|
||||
false,
|
||||
true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>SpreadsheetService</code> object representing the
|
||||
* set APP_IDENTITY and credentials. If both an AuthSub token and
|
||||
* ClientLogin (username/password) credentials are set, the AuthSub
|
||||
* token takes precedence for authentication
|
||||
*
|
||||
* @return an authentication <code>SpreadsheetService</code> instance
|
||||
* @throws EPAuthenticationException
|
||||
*/
|
||||
private SpreadsheetService getSsService()
|
||||
throws EPAuthenticationException {
|
||||
if (this.ssService == null) {
|
||||
SpreadsheetService ssService = new SpreadsheetService(APP_IDENTITY);
|
||||
try {
|
||||
if (ssAuthSubToken != null) {
|
||||
ssService.setAuthSubToken(ssAuthSubToken);
|
||||
} else if (ssUsername != null && ssPassword != null) {
|
||||
ssService.setUserCredentials(ssUsername, ssPassword);
|
||||
}
|
||||
} catch (com.google.gdata.util.AuthenticationException authEx) {
|
||||
throw new EPAuthenticationException("Bad spreadsheets credentials");
|
||||
}
|
||||
this.ssService = ssService;
|
||||
return ssService;
|
||||
} else {
|
||||
return this.ssService;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>CalendarService</code> object representing the
|
||||
* set APP_IDENTITY and credentials. If both an AuthSub token and
|
||||
* ClientLogin (username/password) credentials are set, the AuthSub
|
||||
* token takes precedence for authentication
|
||||
*
|
||||
* @return an authentication <code>CalendarService</code> instance
|
||||
* @throws EPAuthenticationException
|
||||
*/
|
||||
private CalendarService getCalService()
|
||||
throws EPAuthenticationException {
|
||||
if (this.calService == null) {
|
||||
CalendarService calService = new CalendarService(APP_IDENTITY);
|
||||
try {
|
||||
calService.setUserCredentials(calUsername, calPassword);
|
||||
} catch (com.google.gdata.util.AuthenticationException authEx) {
|
||||
throw new EPAuthenticationException("Bad calendar credentials");
|
||||
}
|
||||
this.calService = calService;
|
||||
return calService;
|
||||
} else {
|
||||
return this.calService;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>BaseService</code> object representing the
|
||||
* set APP_IDENTITY and credentials. If both an AuthSub token and
|
||||
* ClientLogin (username/password) credentials are set, the AuthSub
|
||||
* token takes precedence for authentication
|
||||
*
|
||||
* @return an authentication <code>BaseService</code> instance
|
||||
* @throws EPAuthenticationException
|
||||
*/
|
||||
private GoogleBaseService getBaseService()
|
||||
throws EPAuthenticationException {
|
||||
if (this.baseService == null) {
|
||||
GoogleBaseService baseService = new GoogleBaseService(APP_IDENTITY,"none");
|
||||
try {
|
||||
baseService.setUserCredentials(baseUsername, basePassword);
|
||||
} catch (com.google.gdata.util.AuthenticationException authEx) {
|
||||
throw new EPAuthenticationException("Bad calendar credentials");
|
||||
}
|
||||
this.baseService = baseService;
|
||||
return baseService;
|
||||
} else {
|
||||
return this.baseService;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the event objects passed and publishes each of them to Google Base
|
||||
*
|
||||
* @param eventList The list of <code>Event</code>s to publish
|
||||
*/
|
||||
public void publishEventsToBase(List<Event> eventList) {
|
||||
Iterator<Event> i = eventList.iterator();
|
||||
while (i.hasNext()) {
|
||||
Event event = i.next();
|
||||
try {
|
||||
publishEventToBase(event);
|
||||
} catch (EPAuthenticationException e) {
|
||||
System.err.println("Authentication problem when publishing events: " +
|
||||
e.getMessage());
|
||||
} catch (IOException e) {
|
||||
System.err.println("IOException when publishing events: " +
|
||||
e.getMessage());
|
||||
} catch (ServiceException e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("ServiceException when publishing events: " +
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the event objects passed and publishes each of them to Calendar
|
||||
*
|
||||
* @param eventList The list of <code>Event</code>s to publish
|
||||
*/
|
||||
public void publishEventsToCalendar(List<Event> eventList) {
|
||||
Iterator<Event> i = eventList.iterator();
|
||||
while (i.hasNext()) {
|
||||
Event event = i.next();
|
||||
try {
|
||||
publishEventToCalendar(event);
|
||||
} catch (EPAuthenticationException e) {
|
||||
System.err.println("Authentication problem when publishing events: " +
|
||||
e.getMessage());
|
||||
} catch (IOException e) {
|
||||
System.err.println("IOException when publishing events: " +
|
||||
e.getMessage());
|
||||
} catch (ServiceException e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("ServiceException when publishing events: " +
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes an individual event to Calendar
|
||||
*
|
||||
* @param event The <code>Event</code> to publish
|
||||
* @throws EPAuthenticationException
|
||||
* @throws IOException
|
||||
* @throws ServiceException
|
||||
*/
|
||||
private void publishEventToCalendar(Event event)
|
||||
throws EPAuthenticationException, IOException, ServiceException {
|
||||
CalendarService calService = getCalService();
|
||||
CalendarEventEntry entry = null;
|
||||
if (event.getCalendarUrl() != null) {
|
||||
// updating event
|
||||
entry = calService.getEntry(event.getCalendarUrl(),
|
||||
CalendarEventEntry.class);
|
||||
} else {
|
||||
// publishing new event
|
||||
entry = new CalendarEventEntry();
|
||||
}
|
||||
|
||||
// set data on event
|
||||
entry.setTitle(new PlainTextConstruct(event.getTitle()));
|
||||
entry.setContent(new PlainTextConstruct(event.getDescription()));
|
||||
When when = new When();
|
||||
DateTime startDateTime = new DateTime(event.getStartDate());
|
||||
startDateTime.setDateOnly(true);
|
||||
|
||||
// we must add 1 day to the event as the end-date is exclusive
|
||||
Calendar endDateCal = new GregorianCalendar();
|
||||
endDateCal.setTime(event.getEndDate());
|
||||
endDateCal.add(Calendar.DATE, 1);
|
||||
DateTime endDateTime = new DateTime(endDateCal.getTime());
|
||||
endDateTime.setDateOnly(true);
|
||||
|
||||
when.setStartTime(startDateTime);
|
||||
when.setEndTime(endDateTime);
|
||||
entry.getTimes().add(when);
|
||||
if (event.getCalendarUrl() != null) {
|
||||
// updating event
|
||||
entry.update();
|
||||
} else {
|
||||
// insert event
|
||||
CalendarEventEntry resultEntry = calService.insert(calUrl, entry);
|
||||
updateSsEventEditUrl(event.getSsEditUrl(),
|
||||
resultEntry.getEditLink().getHref(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes an individual event to Base
|
||||
*
|
||||
* @param event The <code>Event</code> to publish
|
||||
* @throws EPAuthenticationException
|
||||
* @throws IOException
|
||||
* @throws ServiceException
|
||||
*/
|
||||
private void publishEventToBase(Event event)
|
||||
throws EPAuthenticationException, IOException, ServiceException {
|
||||
GoogleBaseService baseService = getBaseService();
|
||||
GoogleBaseEntry entry = null;
|
||||
if (event.getBaseUrl() != null) {
|
||||
// updating base entry
|
||||
entry = baseService.getEntry(event.getBaseUrl(),
|
||||
GoogleBaseEntry.class);
|
||||
entry = new GoogleBaseEntry();
|
||||
} else {
|
||||
// publishing new entry
|
||||
entry = new GoogleBaseEntry();
|
||||
}
|
||||
|
||||
// prepare an 'events and activities' item for publishing
|
||||
GoogleBaseAttributesExtension gbaseAttributes =
|
||||
entry.getGoogleBaseAttributes();
|
||||
entry.setTitle(new PlainTextConstruct(event.getTitle()));
|
||||
entry.setContent(new PlainTextConstruct(event.getDescription()));
|
||||
gbaseAttributes.setItemType("events and activities");
|
||||
|
||||
// this sample currently only demonstrates publishing all-day events
|
||||
// an event in Google Base must have a start-time and end-time, so
|
||||
// this simulates that by adding 1 day to the end-date specified, if the
|
||||
// start and end times are identical
|
||||
DateTime startDateTime = new DateTime(event.getStartDate());
|
||||
startDateTime.setDateOnly(true);
|
||||
|
||||
DateTime endDateTime = null;
|
||||
|
||||
if (event.getStartDate().equals(event.getEndDate())) {
|
||||
Calendar endDateCal = new GregorianCalendar();
|
||||
endDateCal.setTime(event.getEndDate());
|
||||
endDateCal.add(Calendar.DATE, 1);
|
||||
endDateTime = new DateTime(endDateCal.getTime());
|
||||
} else {
|
||||
endDateTime = new DateTime(event.getEndDate());
|
||||
}
|
||||
endDateTime.setDateOnly(true);
|
||||
|
||||
gbaseAttributes.addDateTimeRangeAttribute("event date range",
|
||||
new DateTimeRange(startDateTime, endDateTime));
|
||||
|
||||
gbaseAttributes.addTextAttribute("event performer", "Google mashup test");
|
||||
gbaseAttributes.addUrlAttribute("performer url", "http://code.google.com/apis/gdata.html");
|
||||
|
||||
if (event.getBaseUrl() != null) {
|
||||
// updating event
|
||||
baseService.update(event.getBaseUrl(), entry);
|
||||
} else {
|
||||
// insert event
|
||||
GoogleBaseEntry resultEntry = baseService.insert(
|
||||
FeedURLFactory.getDefault().getItemsFeedURL(),
|
||||
entry);
|
||||
updateSsEventEditUrl(event.getSsEditUrl(),
|
||||
null,
|
||||
resultEntry.getEditLink().getHref() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the Google Base and/or Calendar edit URLs in the spreadsheet.
|
||||
* The storage of these edit URLs enables further runs of this code to
|
||||
* publish events as new Calendar and Base entries only if the events had
|
||||
* not been previously published
|
||||
*
|
||||
* @param ssEditUrl The edit <code>URL</code> for the spreadsheet
|
||||
* @param calEditUrl The edit URL to be set in the spreadsheet or null
|
||||
* @param baseEditUrl The edit URL to be set in the spreadsheet or null
|
||||
* @throws EPAuthenticationException
|
||||
* @throws IOException
|
||||
* @throws ServiceException
|
||||
*/
|
||||
private void updateSsEventEditUrl(URL ssEditUrl, String calEditUrl,
|
||||
String baseEditUrl)
|
||||
throws EPAuthenticationException, IOException, ServiceException {
|
||||
SpreadsheetService ssService = getSsService();
|
||||
ListEntry ssEntry = ssService.getEntry(ssEditUrl, ListEntry.class);
|
||||
// remove spaces in the URL
|
||||
String calUrlFieldName = fieldMap.getCalendarUrlColumn();
|
||||
if (calEditUrl == null &&
|
||||
(ssEntry.getCustomElements().getValue(calUrlFieldName) == null ||
|
||||
"".equals(ssEntry.getCustomElements().getValue(calUrlFieldName)))){
|
||||
calEditUrl = " ";
|
||||
}
|
||||
if (calEditUrl != null) {
|
||||
ssEntry.getCustomElements().setValueLocal(
|
||||
calUrlFieldName,
|
||||
calEditUrl);
|
||||
}
|
||||
// remove spaces in the URL
|
||||
String baseUrlFieldName = fieldMap.getBaseUrlColumn();
|
||||
if (baseEditUrl == null &&
|
||||
(ssEntry.getCustomElements().getValue(baseUrlFieldName) == null ||
|
||||
"".equals(ssEntry.getCustomElements().getValue(baseUrlFieldName)))){
|
||||
baseEditUrl = " ";
|
||||
}
|
||||
if (baseEditUrl != null) {
|
||||
ssEntry.getCustomElements().setValueLocal(
|
||||
baseUrlFieldName,
|
||||
baseEditUrl);
|
||||
}
|
||||
ssEntry.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a <code>List</code> of <code>SpreadsheetEntry</code> instances
|
||||
* available from the list of Spreadsheets accessible from the authenticated
|
||||
* account.
|
||||
*
|
||||
* @throws EPAuthenticationException
|
||||
*/
|
||||
private List<SpreadsheetEntry> getSsListHelper()
|
||||
throws EPAuthenticationException {
|
||||
List<SpreadsheetEntry> returnList = null;
|
||||
|
||||
try {
|
||||
SpreadsheetService ssService = getSsService();
|
||||
SpreadsheetFeed ssFeed = ssService.getFeed(
|
||||
new URL(SPREADSHEETS_META_FEED),
|
||||
SpreadsheetFeed.class);
|
||||
returnList = ssFeed.getEntries();
|
||||
} catch (com.google.gdata.util.AuthenticationException authEx) {
|
||||
throw new EPAuthenticationException(
|
||||
"SS list read access not available");
|
||||
} catch (com.google.gdata.util.ServiceException svcex) {
|
||||
System.err.println("ServiceException while retrieving " +
|
||||
"available spreadsheets: " + svcex.getMessage());
|
||||
returnList = null;
|
||||
} catch (java.io.IOException ioex) {
|
||||
System.err.println("IOException while retrieving " +
|
||||
"available spreadsheets: " + ioex.getMessage());
|
||||
returnList = null;
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a <code>List</code> of <code>WorksheetEntry</code> instances
|
||||
* available from the list of Worksheets in the specified feed
|
||||
*
|
||||
* @param wsFeedUrl The feed of worksheets
|
||||
* @throws EPAuthenticationException
|
||||
* @return List of worksheets in the specified feed
|
||||
*/
|
||||
private List<WorksheetEntry> getWsListHelper(String wsFeedUrl)
|
||||
throws EPAuthenticationException {
|
||||
List<WorksheetEntry> returnList = null;
|
||||
|
||||
try {
|
||||
SpreadsheetService ssService = getSsService();
|
||||
WorksheetFeed wsFeed = ssService.getFeed(
|
||||
new URL(wsFeedUrl),
|
||||
WorksheetFeed.class);
|
||||
returnList = wsFeed.getEntries();
|
||||
} catch (com.google.gdata.util.AuthenticationException authEx) {
|
||||
throw new EPAuthenticationException(
|
||||
"WS list read access not available");
|
||||
} catch (com.google.gdata.util.ServiceException svcex) {
|
||||
System.err.println("ServiceException while retrieving " +
|
||||
"available worksheets: " + svcex.getMessage());
|
||||
returnList = null;
|
||||
} catch (java.io.IOException ioex) {
|
||||
System.err.println("IOException while retrieving " +
|
||||
"available worksheets: " + ioex.getMessage());
|
||||
returnList = null;
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of column headers in the specified cell feed
|
||||
*
|
||||
* @param cellFeedUrl The cell feed
|
||||
* @return <code>List</code> of column headers as <code>String</code>s
|
||||
* @throws EPAuthenticationException
|
||||
*/
|
||||
public List<String> getColumnList(String cellFeedUrl)
|
||||
throws EPAuthenticationException {
|
||||
List<String> returnList = new LinkedList<String>();
|
||||
List<CellEntry> columnList = getColumnListHelper(cellFeedUrl);
|
||||
for (CellEntry columnEntry : columnList) {
|
||||
returnList.add(columnEntry.getCell().getValue());
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of column headers in the specified cell feed
|
||||
*
|
||||
* @param cellFeedUrl The cell feed
|
||||
* @return <code>List</code> of column headers as <code>CellEntry</code>s
|
||||
* @trhows EPAuthenticationException
|
||||
*/
|
||||
private List<CellEntry> getColumnListHelper(String cellFeedUrl)
|
||||
throws EPAuthenticationException {
|
||||
List<CellEntry> returnList = null;
|
||||
|
||||
try {
|
||||
SpreadsheetService ssService = getSsService();
|
||||
CellFeed cellFeed = ssService.getFeed(
|
||||
new URL(cellFeedUrl + "?min-row=1&max-row=1"),
|
||||
CellFeed.class);
|
||||
returnList = cellFeed.getEntries();
|
||||
} catch (com.google.gdata.util.AuthenticationException authEx) {
|
||||
throw new
|
||||
EPAuthenticationException(
|
||||
"SS read access not available");
|
||||
} catch (com.google.gdata.util.ServiceException svcex) {
|
||||
// log general service exception
|
||||
System.err.println("ServiceException while retrieving " +
|
||||
"column list: " + svcex.getMessage());
|
||||
returnList = null;
|
||||
} catch (java.io.IOException ioex) {
|
||||
System.err.println("IOException while retrieving " +
|
||||
"column list: " + ioex.getMessage());
|
||||
returnList = null;
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all <code>ListEntry</code> objects from the spreadsheet
|
||||
*
|
||||
* @return <code>List</code> of <code>ListEntry</code> instances
|
||||
* @throws EPAuthenticationException
|
||||
*/
|
||||
private List<ListEntry> getSsEntryListHelper()
|
||||
throws EPAuthenticationException {
|
||||
List<ListEntry> returnList = null;
|
||||
|
||||
try {
|
||||
SpreadsheetService ssService = getSsService();
|
||||
ListFeed listFeed = ssService.getFeed(ssUrl, ListFeed.class);
|
||||
returnList = listFeed.getEntries();
|
||||
} catch (com.google.gdata.util.AuthenticationException authEx) {
|
||||
throw new EPAuthenticationException("SS read access not available");
|
||||
} catch (com.google.gdata.util.ServiceException svcex) {
|
||||
System.err.println("ServiceException while retrieving " +
|
||||
"entry list: " + svcex.getMessage());
|
||||
returnList = null;
|
||||
} catch (java.io.IOException ioex) {
|
||||
System.err.println("IOException while retrieving " +
|
||||
"entry list: " + ioex.getMessage());
|
||||
returnList = null;
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
/* Copyright (c) 2008 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 mashups.eventpub;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.configuration.Configuration;
|
||||
import org.apache.commons.configuration.PropertiesConfiguration;
|
||||
|
||||
/**
|
||||
* Servlet to control requests for publishing events from Spreadsheets to
|
||||
* Calendar and Base.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class EventPublisherServlet extends javax.servlet.http.HttpServlet
|
||||
implements javax.servlet.Servlet {
|
||||
|
||||
public static final long serialVersionUID = 1;
|
||||
|
||||
/**
|
||||
* The session attribute in which to store the AuthSub token. The
|
||||
* AuthSub token, after being upgraded from a single-use to a session token,
|
||||
* is held between the requests using the servlet container's session
|
||||
* management capability.
|
||||
*/
|
||||
public static final String SESSION_ATTR_SS_AUTH_TOKEN = "ssAuthSubToken";
|
||||
|
||||
/**
|
||||
* Names of other session attributes
|
||||
*/
|
||||
public static final String SESSION_ATTR_SS_CELL_FEED = "ssCellFeed";
|
||||
public static final String SESSION_ATTR_FIELD_MAP = "fieldMap";
|
||||
public static final String SESSION_ATTR_EVENTS_TO_PUBLISH = "eventsToPublish";
|
||||
|
||||
private Configuration config;
|
||||
|
||||
public EventPublisherServlet() throws Exception {
|
||||
super();
|
||||
config = new PropertiesConfiguration("EventPublisher.properties");
|
||||
}
|
||||
|
||||
private String getCurrentUrl(HttpServletRequest request)
|
||||
throws MalformedURLException {
|
||||
URL currentUrl = new URL(request.getScheme(),
|
||||
request.getServerName(),
|
||||
request.getServerPort(),
|
||||
request.getRequestURI() );
|
||||
return currentUrl.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save AuthSubToken into session
|
||||
*
|
||||
* @param request The request
|
||||
* @param response The response
|
||||
*/
|
||||
private void processAcceptAuthSubToken(HttpServletRequest request,
|
||||
HttpServletResponse response) throws ServletException, IOException {
|
||||
/*
|
||||
* Request is caused by a user being redirected back from AuthSub login
|
||||
*/
|
||||
if (request.getParameter("token") != null ) {
|
||||
EventPublisher ep = new EventPublisher();
|
||||
try {
|
||||
ep.setSsAuthSubToken(request.getParameter("token"), true);
|
||||
request.getSession().setAttribute(SESSION_ATTR_SS_AUTH_TOKEN,
|
||||
ep.getSsAuthSubToken());
|
||||
/*
|
||||
* Redirect to clear the token from the URL and list available
|
||||
* spreadsheets.
|
||||
*/
|
||||
response.sendRedirect("?action=outputSsList");
|
||||
} catch (EPAuthenticationException e) {
|
||||
System.err.println("Authentication exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default action - output intro page
|
||||
*
|
||||
* @param request The request
|
||||
* @param response The response
|
||||
*/
|
||||
private void processOutputIntroPage(HttpServletRequest request,
|
||||
HttpServletResponse response) throws ServletException, IOException {
|
||||
String ssAuthUrl = EventPublisher.getSsAuthSubUrl(
|
||||
getCurrentUrl(request) + "?action=acceptAuthSubToken" );
|
||||
request.setAttribute("ssAuthUrl", ssAuthUrl);
|
||||
RequestDispatcher dispatcher =
|
||||
getServletContext().getRequestDispatcher(
|
||||
"/WEB-INF/jsp/outputIntroPage.jsp");
|
||||
dispatcher.forward(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output list of spreadsheets owned by authenticated account
|
||||
*
|
||||
* @param request The request
|
||||
* @param response The response
|
||||
*/
|
||||
private void processOutputSsList(HttpServletRequest request,
|
||||
HttpServletResponse response) throws ServletException, IOException {
|
||||
EventPublisher ep = new EventPublisher();
|
||||
try {
|
||||
ep.setSsAuthSubToken(
|
||||
(String)request.getSession().getAttribute(SESSION_ATTR_SS_AUTH_TOKEN),
|
||||
false);
|
||||
request.setAttribute("ssList", ep.getSsList());
|
||||
} catch (EPAuthenticationException e) {
|
||||
System.err.println("Authentication exception: " + e.getMessage());
|
||||
}
|
||||
RequestDispatcher dispatcher =
|
||||
getServletContext().getRequestDispatcher(
|
||||
"/WEB-INF/jsp/outputSsList.jsp");
|
||||
dispatcher.forward(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output list of worksheets in chosen spreadsheet
|
||||
*
|
||||
* @param request The request
|
||||
* @param response The response
|
||||
*/
|
||||
private void processOutputWsList(HttpServletRequest request,
|
||||
HttpServletResponse response) throws ServletException, IOException {
|
||||
EventPublisher ep = new EventPublisher();
|
||||
try {
|
||||
ep.setSsAuthSubToken(
|
||||
(String)request.getSession().getAttribute(
|
||||
SESSION_ATTR_SS_AUTH_TOKEN), false);
|
||||
request.setAttribute("token", ep.getSsAuthSubToken());
|
||||
request.setAttribute("wsList",
|
||||
ep.getWsList((String)request.getParameter("wsFeed")));
|
||||
} catch (EPAuthenticationException e) {
|
||||
System.err.println("Authentication exception: " + e.getMessage());
|
||||
}
|
||||
|
||||
RequestDispatcher dispatcher =
|
||||
getServletContext().getRequestDispatcher(
|
||||
"/WEB-INF/jsp/outputWsList.jsp");
|
||||
dispatcher.forward(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output list of columns in chosen worksheet
|
||||
*
|
||||
* @param request The request
|
||||
* @param response The response
|
||||
*/
|
||||
private void processOutputColumnList(HttpServletRequest request,
|
||||
HttpServletResponse response) throws ServletException, IOException {
|
||||
EventPublisher ep = new EventPublisher();
|
||||
try {
|
||||
ep.setSsAuthSubToken(
|
||||
(String)request.getSession().getAttribute(SESSION_ATTR_SS_AUTH_TOKEN),
|
||||
false);
|
||||
request.setAttribute("token", ep.getSsAuthSubToken());
|
||||
request.setAttribute("columnList",
|
||||
ep.getColumnList((String)request.getParameter("cellFeed")));
|
||||
request.getSession().setAttribute(SESSION_ATTR_SS_CELL_FEED,
|
||||
(String)request.getParameter("cellFeed"));
|
||||
} catch (EPAuthenticationException e) {
|
||||
System.err.println("Authentication exception: " + e.getMessage());
|
||||
}
|
||||
|
||||
RequestDispatcher dispatcher =
|
||||
getServletContext().getRequestDispatcher(
|
||||
"/WEB-INF/jsp/outputColumnList.jsp");
|
||||
dispatcher.forward(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists events to be published and also sets the custom field map.
|
||||
*
|
||||
* @param request The request
|
||||
* @param response The response
|
||||
*/
|
||||
private void processListEvents(HttpServletRequest request,
|
||||
HttpServletResponse response) throws ServletException, IOException {
|
||||
EventPublisher ep = new EventPublisher();
|
||||
|
||||
/*
|
||||
* Set the EventPublisher's list feed
|
||||
*/
|
||||
ep.setSsUrl(
|
||||
((String)request.getSession().getAttribute(
|
||||
SESSION_ATTR_SS_CELL_FEED)).replace("cells","list"));
|
||||
|
||||
if (request.getParameter("fdTitle") != null) {
|
||||
SpreadsheetCustomFieldMap fieldMap = new SpreadsheetCustomFieldMap(
|
||||
(String)request.getParameter("fdTitle"),
|
||||
(String)request.getParameter("fdDescription"),
|
||||
(String)request.getParameter("fdStartDate"),
|
||||
(String)request.getParameter("fdEndDate"),
|
||||
(String)request.getParameter("fdLocation"),
|
||||
(String)request.getParameter("fdWebSite"),
|
||||
(String)request.getParameter("fdCalendarUrl"),
|
||||
(String)request.getParameter("fdBaseUrl"));
|
||||
ep.setFieldMap(fieldMap);
|
||||
request.getSession().setAttribute(SESSION_ATTR_FIELD_MAP, fieldMap);
|
||||
} else {
|
||||
ep.setFieldMap(
|
||||
(SpreadsheetCustomFieldMap)
|
||||
request.getSession().getAttribute(SESSION_ATTR_FIELD_MAP));
|
||||
}
|
||||
|
||||
try {
|
||||
ep.setSsAuthSubToken(
|
||||
(String)request.getSession().getAttribute(SESSION_ATTR_SS_AUTH_TOKEN),
|
||||
false);
|
||||
List<Event> listEvents = ep.getEventsFromSpreadsheet();
|
||||
request.setAttribute("events", listEvents);
|
||||
request.getSession().setAttribute(SESSION_ATTR_EVENTS_TO_PUBLISH,
|
||||
listEvents);
|
||||
javax.servlet.RequestDispatcher dispatcher =
|
||||
getServletContext().getRequestDispatcher(
|
||||
"/WEB-INF/jsp/outputEventList.jsp");
|
||||
dispatcher.forward(request, response);
|
||||
} catch (EPAuthenticationException e) {
|
||||
System.err.println("Authentication exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish all events to Calendar and/or Base
|
||||
*
|
||||
* @param request The request
|
||||
* @param response The response
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void processPublishEvents(HttpServletRequest request,
|
||||
HttpServletResponse response) throws ServletException, IOException {
|
||||
EventPublisher ep = new EventPublisher();
|
||||
ep.setFieldMap((SpreadsheetCustomFieldMap)
|
||||
request.getSession().getAttribute(SESSION_ATTR_FIELD_MAP));
|
||||
try {
|
||||
ep.setSsAuthSubToken(
|
||||
(String)request.getSession().getAttribute(SESSION_ATTR_SS_AUTH_TOKEN),
|
||||
false);
|
||||
} catch (EPAuthenticationException e) {
|
||||
System.err.println("Authentication exception: " + e.getMessage());
|
||||
}
|
||||
|
||||
LinkedList<Event> eventList =
|
||||
(LinkedList<Event>)request.getSession().getAttribute(
|
||||
SESSION_ATTR_EVENTS_TO_PUBLISH);
|
||||
|
||||
if (request.getParameter("calendar") != null &&
|
||||
"checked".equals(request.getParameter("calendar"))) {
|
||||
String calUsername = config.getString("calendar.username");
|
||||
String calPassword = config.getString("calendar.password");
|
||||
String calUrl = config.getString("calendar.url");
|
||||
ep.setCalUsernamePassword(calUsername, calPassword);
|
||||
ep.setCalUrl(calUrl);
|
||||
ep.publishEventsToCalendar(eventList);
|
||||
}
|
||||
if (request.getParameter("base") != null &&
|
||||
"checked".equals(request.getParameter("base"))) {
|
||||
String baseUsername = config.getString("gbase.username");
|
||||
String basePassword = config.getString("gbase.password");
|
||||
ep.setBaseUsernamePassword(baseUsername, basePassword);
|
||||
ep.publishEventsToBase(eventList);
|
||||
}
|
||||
javax.servlet.RequestDispatcher dispatcher =
|
||||
getServletContext().getRequestDispatcher(
|
||||
"/WEB-INF/jsp/outputPublishingResults.jsp");
|
||||
dispatcher.forward(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process all requests to this servlet
|
||||
*
|
||||
* @param request The request
|
||||
* @param response The response
|
||||
*/
|
||||
protected void doPost(HttpServletRequest request,
|
||||
HttpServletResponse response) throws ServletException, IOException {
|
||||
/*
|
||||
* Determine action attempted
|
||||
*/
|
||||
String action = (request.getParameter("action"))==null?
|
||||
"outputIntroPage":request.getParameter("action");
|
||||
|
||||
if ("outputIntroPage".equals(action)) {
|
||||
processOutputIntroPage(request, response);
|
||||
} else if ("acceptAuthSubToken".equals(action)) {
|
||||
processAcceptAuthSubToken(request, response);
|
||||
} else if ("outputSsList".equals(action)) {
|
||||
processOutputSsList(request, response);
|
||||
} else if ("outputWsList".equals(action)) {
|
||||
processOutputWsList(request, response);
|
||||
} else if ("outputColumnList".equals(action)) {
|
||||
processOutputColumnList(request, response);
|
||||
} else if ("listEvents".equals(action)) {
|
||||
processListEvents(request, response);
|
||||
} else if ("publish".equals(action)) {
|
||||
processPublishEvents(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process GET requests by calling the doPost method
|
||||
*
|
||||
* @param request The request
|
||||
* @param response The response
|
||||
*/
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
doPost(request, response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/* Copyright (c) 2008 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 mashups.eventpub;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Store the mapping between Spreadsheet columns and needed data
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class SpreadsheetCustomFieldMap {
|
||||
|
||||
public static final long serialVersionUID = 1L;
|
||||
|
||||
private HashMap<String, String> fieldMap = null;
|
||||
|
||||
/**
|
||||
* Constructs a new SpreadsheetCustomFieldMap
|
||||
*
|
||||
* @param title Column name for event title
|
||||
* @param description Column name for event description
|
||||
* @param start Column name for event start date
|
||||
* @param end Column name for event end date
|
||||
* @param location Column name for the event location
|
||||
* @param website Column name for the event website
|
||||
* @param calendarUrl Column name for the calendar event edit URL
|
||||
* @param baseUrl Column name for the base event edit URL
|
||||
*/
|
||||
public SpreadsheetCustomFieldMap(String title, String description,
|
||||
String start, String end, String location, String website,
|
||||
String calendarUrl, String baseUrl) {
|
||||
fieldMap = new HashMap<String, String>();
|
||||
setField("title", title);
|
||||
setField("description", description);
|
||||
setField("start", start);
|
||||
setField("end", end);
|
||||
setField("location", location);
|
||||
setField("website", website);
|
||||
setField("calendarUrl", calendarUrl);
|
||||
setField("baseUrl", baseUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the field in the fieldMap, stripping any whitespaces from the
|
||||
* name of the column in the spreadsheet
|
||||
*
|
||||
* @param name The name of the field needed
|
||||
* @param value The name of the column in the spreadsheet
|
||||
*/
|
||||
public void setField(String name, String value) {
|
||||
fieldMap.put(name, value.replace(" ", ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the column identifying the title
|
||||
*
|
||||
* @return Column name for the event title
|
||||
*/
|
||||
public String getTitleColumn() {
|
||||
return (String)fieldMap.get("title");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the column identifying the description
|
||||
*
|
||||
* @return Column name for the event description
|
||||
*/
|
||||
public String getDescriptionColumn() {
|
||||
return (String)fieldMap.get("description");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the column identifying the start
|
||||
*
|
||||
* @return Column name for the event start
|
||||
*/
|
||||
public String getStartColumn() {
|
||||
return (String)fieldMap.get("start");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the column identifying the end
|
||||
*
|
||||
* @return Column name for the event end
|
||||
*/
|
||||
public String getEndColumn() {
|
||||
return (String)fieldMap.get("end");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the column identifying the location
|
||||
*
|
||||
* @return Column name for the event location
|
||||
*/
|
||||
public String getLocationColumn() {
|
||||
return (String)fieldMap.get("location");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the column identifying the website
|
||||
*
|
||||
* @return Column name for the event website
|
||||
*/
|
||||
public String getWebsiteColumn() {
|
||||
return (String)fieldMap.get("website");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the column identifying the calendarUrl
|
||||
*
|
||||
* @return Column name for the event calendarUrl
|
||||
*/
|
||||
public String getCalendarUrlColumn() {
|
||||
return (String)fieldMap.get("calendarUrl");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the column identifying the baseUrl
|
||||
*
|
||||
* @return Column name for the event baseUrl
|
||||
*/
|
||||
public String getBaseUrlColumn() {
|
||||
return (String)fieldMap.get("baseUrl");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user