Skip to content
This repository was archived by the owner on Jan 5, 2026. It is now read-only.

Commit 04f6e34

Browse files
Fix for AuthSub encoding/decoding.
Analytics API updates
1 parent ff4a303 commit 04f6e34

File tree

12 files changed

+528
-29
lines changed

12 files changed

+528
-29
lines changed

RELEASE_NOTES.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
Google Data API - Release Notes
2+
Notes for v1.41.5
3+
-----------------
4+
o Update Analytics API
5+
o Fix AuthSub encoding/decoding issue.
6+
27
Notes for v1.41.4
38
-----------------
49
o Updates Apps For Your Domain API
231 Bytes
Binary file not shown.

java/src/com/google/gdata/client/analytics/AnalyticsService.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.google.gdata.data.analytics.CombinationFeed;
2525
import com.google.gdata.data.analytics.DataFeed;
2626
import com.google.gdata.data.analytics.ExperimentFeed;
27+
import com.google.gdata.data.analytics.ManagementFeed;
2728
import com.google.gdata.data.analytics.SectionFeed;
2829
import com.google.gdata.data.analytics.VariationFeed;
2930
import com.google.gdata.util.Version;
@@ -68,8 +69,8 @@ public static final class Versions {
6869
public static final Version V2_1 = new Version(AnalyticsService.class,
6970
"2.1", Service.Versions.V2_1);
7071

71-
/** Version {@code 2.2}. This version adds generalized account feeds, and
72-
* is based on GData version 2.1. */
72+
/** Version {@code 2.2}. This version adds Management API feeds, and is
73+
* based on GData version 2.1. */
7374
public static final Version V2_2 = new Version(AnalyticsService.class,
7475
"2.2", Service.Versions.V2_1);
7576

@@ -80,7 +81,7 @@ private Versions() {}
8081
* Default GData version used by the Google Analytics Data Export API.
8182
*/
8283
public static final Version DEFAULT_VERSION =
83-
Service.initServiceVersion(AnalyticsService.class, Versions.V2_1);
84+
Service.initServiceVersion(AnalyticsService.class, Versions.V2_2);
8485

8586
/**
8687
* Constructs an instance connecting to the Google Analytics Data Export API
@@ -160,6 +161,7 @@ private void declareExtensions() {
160161
new CombinationFeed().declareExtensions(extProfile);
161162
new DataFeed().declareExtensions(extProfile);
162163
new ExperimentFeed().declareExtensions(extProfile);
164+
new ManagementFeed().declareExtensions(extProfile);
163165
new SectionFeed().declareExtensions(extProfile);
164166
new VariationFeed().declareExtensions(extProfile);
165167
}

java/src/com/google/gdata/client/http/AuthSubUtil.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
import java.io.FileInputStream;
2727
import java.io.IOException;
2828
import java.io.InputStreamReader;
29+
import java.io.UnsupportedEncodingException;
2930
import java.net.HttpURLConnection;
3031
import java.net.URL;
32+
import java.net.URLDecoder;
3133
import java.security.GeneralSecurityException;
3234
import java.security.KeyStore;
3335
import java.security.PrivateKey;
@@ -207,19 +209,30 @@ public static String getTokenFromReply(URL url) {
207209
/**
208210
* Parses and returns the AuthSub token returned by Google on a successful
209211
* AuthSub login request. The token will be appended as a query parameter
210-
* to the next URL specified while making the AuthSub request.
212+
* to the "next" URL specified while making the AuthSub request.
211213
*
212214
* @param queryString the query portion of the redirected-to URL containing
213-
* the token
214-
* @return the AuthSub token returned by Google
215+
* the token (as the server received it; i.e. what
216+
* {@code httpServletRequest.getQueryString()} returns)
217+
* @return the AuthSub token returned by Google; {@code null} if there is no
218+
* token present in {@code queryString}. The token text will have
219+
* been run through {@link URLDecoder} already, and will not need any
220+
* additional decoding before use; however, the token string will
221+
* not contain percent ({@code %}) characters and therefore
222+
* additional url-decoding will do no harm.
215223
*/
216224
public static String getTokenFromReply(String queryString) {
217225

218226
// Parse the query parameters
219227
Map<String, String> params =
220228
StringUtil.string2Map(queryString, "&", "=", true /*stripEntry*/);
221229
params = StringUtil.lowercaseKeys(params);
222-
return params.get("token");
230+
String encoded = params.get("token");
231+
try {
232+
return encoded == null ? null : URLDecoder.decode(encoded, "UTF-8");
233+
} catch (UnsupportedEncodingException e) {
234+
throw new RuntimeException(e); // Can't happen - UTF-8 in all jvms
235+
}
223236
}
224237

225238

java/src/com/google/gdata/client/http/HttpGDataRequest.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -546,19 +546,23 @@ public void execute() throws IOException, ServiceException {
546546
*/
547547
protected void checkResponse() throws IOException, ServiceException {
548548

549-
if (httpConn.getResponseCode() >= 300) {
550-
handleErrorResponse();
551-
} else if (isOAuthProxyErrorResponse()) {
549+
if (isOAuthProxyErrorResponse()) {
552550
handleOAuthProxyErrorResponse();
551+
} else if (httpConn.getResponseCode() >= 300) {
552+
handleErrorResponse();
553553
}
554554
}
555555

556556
/** Whether or not the http response comes from the OAuth Proxy. */
557-
private boolean isOAuthProxyErrorResponse() {
557+
private boolean isOAuthProxyErrorResponse() throws IOException {
558558
Set<String> headers = httpConn.getHeaderFields().keySet();
559-
return headers.contains(OAuthProxyProtocol.Header.X_OAUTH_APPROVAL_URL)
560-
|| headers.contains(OAuthProxyProtocol.Header.X_OAUTH_ERROR)
561-
|| headers.contains(OAuthProxyProtocol.Header.X_OAUTH_ERROR_TEXT);
559+
boolean isOAuthRedirectToApproval =
560+
headers.contains(OAuthProxyProtocol.Header.X_OAUTH_APPROVAL_URL);
561+
boolean isOtherOAuthError =
562+
httpConn.getResponseCode() == HttpURLConnection.HTTP_OK
563+
&& (headers.contains(OAuthProxyProtocol.Header.X_OAUTH_ERROR)
564+
|| headers.contains(OAuthProxyProtocol.Header.X_OAUTH_ERROR_TEXT));
565+
return isOAuthRedirectToApproval || isOtherOAuthError;
562566
}
563567

564568
/**

java/src/com/google/gdata/data/analytics/AccountEntry.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ public void declareExtensions(ExtensionProfile extProfile) {
5757
extProfile.declare(AccountEntry.class, Goal.getDefaultDescription(false,
5858
true));
5959
new Goal().declareExtensions(extProfile);
60+
extProfile.declare(AccountEntry.class,
61+
AnalyticsLink.getDefaultDescription(false, true));
6062
extProfile.declare(AccountEntry.class, Property.getDefaultDescription(false,
6163
true));
6264
extProfile.declare(AccountEntry.class, TableId.getDefaultDescription(true,
@@ -209,5 +211,4 @@ public String getProperty(String name) {
209211
}
210212
return null;
211213
}
212-
213214
}
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/* Copyright (c) 2008 Google Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
17+
package com.google.gdata.data.analytics;
18+
19+
import com.google.gdata.data.AttributeGenerator;
20+
import com.google.gdata.data.AttributeHelper;
21+
import com.google.gdata.data.ExtensionDescription;
22+
import com.google.gdata.data.ExtensionProfile;
23+
import com.google.gdata.data.Link;
24+
import com.google.gdata.util.Namespaces;
25+
import com.google.gdata.util.ParseException;
26+
import com.google.gdata.util.XmlParser.ElementHandler;
27+
28+
import org.xml.sax.Attributes;
29+
30+
/**
31+
* Extends the base Link class with Analytics extensions.
32+
*
33+
*
34+
*/
35+
@ExtensionDescription.Default(
36+
nsAlias = "atom",
37+
nsUri = Namespaces.atom,
38+
localName = AnalyticsLink.XML_NAME)
39+
public class AnalyticsLink extends Link {
40+
41+
/** XML element name */
42+
static final String XML_NAME = "link";
43+
44+
/** XML "gd:targetKind" attribute name */
45+
private static final String TARGETKIND = "gd:targetKind";
46+
47+
/** Kind of feed/entry the href is pointing to */
48+
private String targetKind = null;
49+
50+
/** Link relation type. */
51+
public static final class Rel {
52+
53+
/** Represents a link to a CHILD feed. */
54+
public static final String CHILD = AnalyticsNamespace.GA_PREFIX + "child";
55+
56+
/** Represents a link to a PARENT entry. */
57+
public static final String PARENT = AnalyticsNamespace.GA_PREFIX + "parent";
58+
59+
}
60+
61+
/**
62+
* Default mutable constructor.
63+
*/
64+
public AnalyticsLink() {
65+
super();
66+
}
67+
68+
/**
69+
* Immutable constructor.
70+
*
71+
* @param targetKind kind of feed/entry the href is pointing to.
72+
*/
73+
public AnalyticsLink(String targetKind) {
74+
super();
75+
setTargetKind(targetKind);
76+
setImmutable(true);
77+
}
78+
79+
/**
80+
* Returns the kind of feed/entry the href is pointing to.
81+
*
82+
* @return kind of feed/entry the href is pointing to
83+
*/
84+
public String getTargetKind() {
85+
return targetKind;
86+
}
87+
88+
/**
89+
* Sets the kind of feed/entry the href is pointing to.
90+
*
91+
* @param targetKind kind of feed/entry the href is pointing to or
92+
* <code>null</code> to reset
93+
*/
94+
public void setTargetKind(String targetKind) {
95+
throwExceptionIfImmutable();
96+
this.targetKind = targetKind;
97+
}
98+
99+
/**
100+
* Returns whether it has the kind of feed/entry the href is pointing to.
101+
*
102+
* @return whether it has the kind of feed/entry the href is pointing to
103+
*/
104+
public boolean hasTargetKind() {
105+
return getTargetKind() != null;
106+
}
107+
108+
@Override
109+
protected void validate() {
110+
}
111+
112+
/**
113+
* Returns the extension description, specifying whether it is required, and
114+
* whether it is repeatable.
115+
*
116+
* @param required whether it is required
117+
* @param repeatable whether it is repeatable
118+
* @return extension description
119+
*/
120+
public static ExtensionDescription getDefaultDescription(boolean required,
121+
boolean repeatable) {
122+
ExtensionDescription desc =
123+
ExtensionDescription.getDefaultDescription(AnalyticsLink.class);
124+
desc.setRequired(required);
125+
desc.setRepeatable(repeatable);
126+
return desc;
127+
}
128+
129+
@Override
130+
protected void putAttributes(AttributeGenerator generator) {
131+
generator.put(TARGETKIND, targetKind);
132+
}
133+
134+
@Override
135+
protected void consumeAttributes(AttributeHelper helper) throws ParseException
136+
{
137+
targetKind = helper.consume("targetKind", false);
138+
}
139+
140+
@Override
141+
public boolean equals(Object obj) {
142+
if (this == obj) {
143+
return true;
144+
}
145+
if (!sameClassAs(obj)) {
146+
return false;
147+
}
148+
AnalyticsLink other = (AnalyticsLink) obj;
149+
return eq(targetKind, other.targetKind);
150+
}
151+
152+
@Override
153+
public int hashCode() {
154+
int result = getClass().hashCode();
155+
if (targetKind != null) {
156+
result = 37 * result + targetKind.hashCode();
157+
}
158+
return result;
159+
}
160+
161+
@Override
162+
public String toString() {
163+
return "{AnalyticsLink targetKind=" + targetKind + " " + super.toString() +
164+
"}";
165+
}
166+
167+
168+
@Override
169+
public ElementHandler getHandler(ExtensionProfile p, String namespace,
170+
String localName,
171+
Attributes attrs) {
172+
return new AnalyticsLinkHandler(p);
173+
}
174+
175+
/**
176+
* An XML Parser for 'atom:link' extension for Google Analytics.
177+
*/
178+
class AnalyticsLinkHandler extends AtomHandler {
179+
180+
public AnalyticsLinkHandler(ExtensionProfile extProfile) {
181+
super(extProfile, AnalyticsLink.class);
182+
}
183+
184+
/**
185+
* Adds parsing for 'gd:targetKind' attribute.
186+
*/
187+
@Override
188+
public void processAttribute(String namespace, String localName,
189+
String value)
190+
throws ParseException {
191+
super.processAttribute(namespace, localName, value);
192+
193+
if (namespace.equals(Namespaces.g) && localName.equals("targetKind")) {
194+
targetKind = value;
195+
}
196+
}
197+
}
198+
}

java/src/com/google/gdata/data/analytics/DataEntry.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ public void declareExtensions(ExtensionProfile extProfile) {
5454
super.declareExtensions(extProfile);
5555
extProfile.declare(DataEntry.class, Dimension.getDefaultDescription(false,
5656
true));
57+
extProfile.declare(DataEntry.class,
58+
AnalyticsLink.getDefaultDescription(false, true));
5759
extProfile.declare(DataEntry.class, Metric.getDefaultDescription(false,
5860
true));
5961
}

0 commit comments

Comments
 (0)