Inital commit

This commit is contained in:
Tilman
2011-10-26 09:44:02 +02:00
commit 5971f4b417
1813 changed files with 737837 additions and 0 deletions
+100
View File
@@ -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=
+175
View File
@@ -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");
}
}