├── .gitignore
├── CONTRIBUTING.md
├── README.md
├── pom.xml
└── src
└── main
├── java
└── com
│ └── google
│ └── glassware
│ ├── AttachmentProxyServlet.java
│ ├── AuthFilter.java
│ ├── AuthServlet.java
│ ├── AuthUtil.java
│ ├── ListableMemoryCredentialStore.java
│ ├── MainServlet.java
│ ├── MirrorClient.java
│ ├── NewUserBootstrapper.java
│ ├── NotifyServlet.java
│ ├── ReauthFilter.java
│ └── WebUtil.java
├── resources
└── oauth.properties
└── webapp
├── WEB-INF
└── web.xml
├── index.jsp
└── static
├── bootstrap
├── css
│ ├── bootstrap-responsive.css
│ ├── bootstrap-responsive.min.css
│ ├── bootstrap.css
│ └── bootstrap.min.css
├── img
│ ├── glyphicons-halflings-white.png
│ └── glyphicons-halflings.png
└── js
│ ├── bootstrap.js
│ └── bootstrap.min.js
├── images
├── chipotle-tube-640x360.jpg
├── drill.png
├── keys.png
├── saturn-eclipse.jpg
└── send_to_glass_64x64.png
└── main.css
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Package Files #
4 | *.war
5 | *.ear
6 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to become a contributor and submit your own code
2 |
3 | ## Contributor License Agreements
4 |
5 | We'd love to accept your sample apps and patches! Before we can take them, we
6 | have to jump a couple of legal hurdles.
7 |
8 | Please fill out either the individual or corporate Contributor License Agreement
9 | (CLA).
10 |
11 | * If you are an individual writing original source code and you're sure you
12 | own the intellectual property, then you'll need to sign an [individual CLA]
13 | (http://code.google.com/legal/individual-cla-v1.0.html).
14 | * If you work for a company that wants to allow you to contribute your work,
15 | then you'll need to sign a [corporate CLA]
16 | (http://code.google.com/legal/corporate-cla-v1.0.html).
17 |
18 | Follow either of the two links above to access the appropriate CLA and
19 | instructions for how to sign and return it. Once we receive it, we'll be able to
20 | accept your pull requests.
21 |
22 | ## Contributing a Patch
23 |
24 | 1. Sign a Contributor License Agreement, if you have not yet done so (see
25 | details above).
26 | 1. Create your change to the repo in question.
27 | * Fork the desired repo, develop and test your code changes.
28 | * Ensure that your code is clear and comprehensible.
29 | * Ensure that your code has an appropriate set of unit tests which all pass.
30 | 1. Submit a pull request.
31 | 1. The repo owner will review your request. If it is approved, the change will
32 | be merged. If it needs additional work, the repo owner will respond with
33 | useful comments.
34 |
35 | ## Contributing a New Sample App
36 |
37 | 1. Sign a Contributor License Agreement, if you have not yet done so (see
38 | details above).
39 | 1. Create your own repo for your app following this naming convention:
40 | * mirror-{app-name}-{language or plaform}
41 | * apps: quickstart, photohunt-server, photohunt-client
42 | * example: mirror-quickstart-android
43 | * For multi-language apps, concatenate the primary languages like this:
44 | mirror-photohunt-server-java-python.
45 |
46 | 1. Create your sample app in this repo.
47 | * Be sure to clone the README.md, CONTRIBUTING.md and LICENSE files from the
48 | googleglass repo.
49 | * Ensure that your code is clear and comprehensible.
50 | * Ensure that your code has an appropriate set of unit tests which all pass.
51 | * Instructional value is the top priority when evaluating new app proposals for
52 | this collection of repos.
53 | 1. Submit a request to fork your repo in googleglass organization.
54 | 1. The repo owner will review your request. If it is approved, the sample will
55 | be merged. If it needs additional work, the repo owner will respond with
56 | useful comments.
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Google Mirror API's Quickstart for Java
2 | ========================
3 |
4 | The documentation for this quickstart is maintained on developers.google.com.
5 | Please see here for more information:
6 | https://developers.google.com/glass/quickstart/java
7 |
8 | ## License
9 | Code for this project is licensed under [APL 2.0](http://www.apache.org/licenses/LICENSE-2.0.html)
10 | and content is licensed under the
11 | [Creative Commons Attribution 3.0 License](http://creativecommons.org/licenses/by/3.0/).
12 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
18 |
19 | 4.0.0
20 | com.google
21 | glass-java-starter
22 | 0.1-SNAPSHOT
23 |
24 | UTF-8
25 |
26 |
27 |
28 |
29 |
30 | com.google.apis
31 | google-api-services-mirror
32 | v1-rev26-1.17.0-rc
33 |
34 |
35 | com.google.http-client
36 | google-http-client-jackson2
37 | 1.17.0-rc
38 |
39 |
40 |
41 |
42 | org.mortbay.jetty
43 | jetty
44 | 6.1.14
45 |
46 |
47 | org.mortbay.jetty
48 | jetty-util
49 | 6.1.14
50 |
51 |
52 | org.mortbay.jetty
53 | jetty-plus
54 | 6.1.14
55 |
56 |
57 | org.mortbay.jetty
58 | jsp-2.1
59 | 6.1.14
60 |
61 |
62 | org.mortbay.jetty
63 | jsp-api-2.1
64 | 6.1.14
65 |
66 |
67 |
68 |
69 | org.apache.commons
70 | commons-lang3
71 | 3.1
72 |
73 |
74 | org.codehaus.jackson
75 | jackson-core-asl
76 | 1.9.11
77 |
78 |
79 | org.codehaus.jackson
80 | jackson-mapper-asl
81 | 1.9.11
82 |
83 |
84 | javax.servlet
85 | servlet-api
86 | 2.5
87 |
88 |
89 | commons-logging
90 | commons-logging
91 | 1.1.2
92 |
93 |
94 | commons-codec
95 | commons-codec
96 | 1.7
97 |
98 |
99 | com.google.guava
100 | guava
101 | 14.0.1
102 |
103 |
104 |
105 |
106 |
107 |
108 | org.mortbay.jetty
109 | maven-jetty-plugin
110 | 6.1.26
111 |
112 | /
113 |
114 |
115 |
116 | org.apache.maven.plugins
117 | maven-compiler-plugin
118 | 3.1
119 |
120 | 1.6
121 | 1.6
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/src/main/java/com/google/glassware/AttachmentProxyServlet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.google.glassware;
17 |
18 | import com.google.api.client.auth.oauth2.Credential;
19 | import com.google.common.io.ByteStreams;
20 |
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.util.logging.Logger;
24 |
25 | import javax.servlet.ServletException;
26 | import javax.servlet.http.HttpServlet;
27 | import javax.servlet.http.HttpServletRequest;
28 | import javax.servlet.http.HttpServletResponse;
29 |
30 | /**
31 | * Allows logged in users to view their timeline item attachments by proxying
32 | * their app engine session to their OAuth session.
33 | *
34 | * @author Jenny Murphy - http://google.com/+JennyMurphy
35 | */
36 | public class AttachmentProxyServlet extends HttpServlet {
37 | private static final Logger LOG = Logger.getLogger(AttachmentProxyServlet.class.getSimpleName());
38 |
39 | @Override
40 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
41 | IOException {
42 | String attachmentId = req.getParameter("attachment");
43 | String timelineItemId = req.getParameter("timelineItem");
44 | if (attachmentId == null || timelineItemId == null) {
45 | LOG.warning("attempted to load image attachment with missing IDs");
46 | resp.sendError(400);
47 | }
48 | // identify the viewing user
49 | Credential credential = AuthUtil.getCredential(req);
50 |
51 | // Get the content type
52 | String contentType =
53 | MirrorClient.getAttachmentContentType(credential, timelineItemId, attachmentId);
54 |
55 | // Get the attachment bytes
56 | InputStream attachmentInputStream =
57 | MirrorClient.getAttachmentInputStream(credential, timelineItemId, attachmentId);
58 |
59 | // Write it out
60 | resp.setContentType(contentType);
61 | ByteStreams.copy(attachmentInputStream, resp.getOutputStream());
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/google/glassware/AuthFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.google.glassware;
17 |
18 | import java.io.IOException;
19 | import java.util.logging.Logger;
20 |
21 | import javax.servlet.Filter;
22 | import javax.servlet.FilterChain;
23 | import javax.servlet.FilterConfig;
24 | import javax.servlet.ServletException;
25 | import javax.servlet.ServletRequest;
26 | import javax.servlet.ServletResponse;
27 | import javax.servlet.http.HttpServletRequest;
28 | import javax.servlet.http.HttpServletResponse;
29 |
30 | /**
31 | * A filter which ensures that prevents unauthenticated users from accessing the
32 | * web app
33 | *
34 | * @author Jenny Murphy - http://google.com/+JennyMurphy
35 | */
36 | public class AuthFilter implements Filter {
37 | private static final Logger LOG = Logger.getLogger(AuthFilter.class.getSimpleName());
38 |
39 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
40 | throws IOException, ServletException {
41 | if (response instanceof HttpServletResponse && request instanceof HttpServletRequest) {
42 | HttpServletRequest httpRequest = (HttpServletRequest) request;
43 | HttpServletResponse httpResponse = (HttpServletResponse) response;
44 |
45 | // skip auth for static content, middle of auth flow, notify servlet
46 | if (httpRequest.getRequestURI().startsWith("/static") ||
47 | httpRequest.getRequestURI().equals("/oauth2callback") ||
48 | httpRequest.getRequestURI().equals("/notify")) {
49 | LOG.info("Skipping auth check during auth flow");
50 | filterChain.doFilter(request, response);
51 | return;
52 | }
53 |
54 | LOG.fine("Checking to see if anyone is logged in");
55 | if (AuthUtil.getUserId(httpRequest) == null
56 | || AuthUtil.getCredential(AuthUtil.getUserId(httpRequest)) == null
57 | || AuthUtil.getCredential(AuthUtil.getUserId(httpRequest)).getAccessToken() == null) {
58 | // redirect to auth flow
59 | httpResponse.sendRedirect(WebUtil.buildUrl(httpRequest, "/oauth2callback"));
60 | return;
61 | }
62 |
63 | // Things checked out OK :)
64 | filterChain.doFilter(request, response);
65 | } else {
66 | LOG.warning("Unexpected non HTTP servlet response. Proceeding anyway.");
67 | filterChain.doFilter(request, response);
68 | }
69 | }
70 |
71 | @Override
72 | public void init(FilterConfig filterConfig) throws ServletException {
73 | }
74 |
75 | @Override
76 | public void destroy() {
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/com/google/glassware/AuthServlet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.google.glassware;
17 |
18 | import com.google.api.client.auth.oauth2.AuthorizationCodeFlow;
19 | import com.google.api.client.auth.oauth2.TokenResponse;
20 | import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
21 | import com.google.api.client.http.GenericUrl;
22 |
23 | import java.io.IOException;
24 | import java.util.logging.Logger;
25 |
26 | import javax.servlet.http.HttpServlet;
27 | import javax.servlet.http.HttpServletRequest;
28 | import javax.servlet.http.HttpServletResponse;
29 |
30 | /**
31 | * This servlet manages the OAuth 2.0 dance
32 | *
33 | * @author Jenny Murphy - http://google.com/+JennyMurphy
34 | */
35 | public class AuthServlet extends HttpServlet {
36 | private static final Logger LOG = Logger.getLogger(AuthServlet.class.getSimpleName());
37 |
38 | @Override
39 | protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
40 | // If something went wrong, log the error message.
41 | if (req.getParameter("error") != null) {
42 | LOG.severe("Something went wrong during auth: " + req.getParameter("error"));
43 | res.setContentType("text/plain");
44 | res.getWriter().write("Something went wrong during auth. Please check your log for details");
45 | return;
46 | }
47 |
48 | // If we have a code, finish the OAuth 2.0 dance
49 | if (req.getParameter("code") != null) {
50 | LOG.info("Got a code. Attempting to exchange for access token.");
51 |
52 | AuthorizationCodeFlow flow = AuthUtil.newAuthorizationCodeFlow();
53 | TokenResponse tokenResponse =
54 | flow.newTokenRequest(req.getParameter("code"))
55 | .setRedirectUri(WebUtil.buildUrl(req, "/oauth2callback")).execute();
56 |
57 | // Extract the Google User ID from the ID token in the auth response
58 | String userId = ((GoogleTokenResponse) tokenResponse).parseIdToken().getPayload().getUserId();
59 |
60 | LOG.info("Code exchange worked. User " + userId + " logged in.");
61 |
62 | // Set it into the session
63 | AuthUtil.setUserId(req, userId);
64 | flow.createAndStoreCredential(tokenResponse, userId);
65 |
66 | // The dance is done. Do our bootstrapping stuff for this user
67 | NewUserBootstrapper.bootstrapNewUser(req, userId);
68 |
69 | // Redirect back to index
70 | res.sendRedirect(WebUtil.buildUrl(req, "/"));
71 | return;
72 | }
73 |
74 | // Else, we have a new flow. Initiate a new flow.
75 | LOG.info("No auth context found. Kicking off a new auth flow.");
76 |
77 | AuthorizationCodeFlow flow = AuthUtil.newAuthorizationCodeFlow();
78 | GenericUrl url =
79 | flow.newAuthorizationUrl().setRedirectUri(WebUtil.buildUrl(req, "/oauth2callback"));
80 | url.set("approval_prompt", "force");
81 | res.sendRedirect(url.build());
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/com/google/glassware/AuthUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.google.glassware;
17 |
18 | import com.google.api.client.auth.oauth2.AuthorizationCodeFlow;
19 | import com.google.api.client.auth.oauth2.Credential;
20 | import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
21 | import com.google.api.client.http.javanet.NetHttpTransport;
22 |
23 | import com.google.api.client.json.jackson2.JacksonFactory;
24 |
25 | import java.io.File;
26 | import java.io.FileInputStream;
27 | import java.io.IOException;
28 | import java.net.URISyntaxException;
29 | import java.net.URL;
30 | import java.util.Collections;
31 | import java.util.List;
32 | import java.util.Properties;
33 | import java.util.logging.Logger;
34 |
35 | import javax.servlet.http.HttpServletRequest;
36 | import javax.servlet.http.HttpSession;
37 |
38 | /**
39 | * A collection of utility functions that simplify common authentication and
40 | * user identity tasks
41 | *
42 | * @author Jenny Murphy - http://google.com/+JennyMurphy
43 | */
44 | public class AuthUtil {
45 | public static ListableMemoryCredentialStore store = new ListableMemoryCredentialStore();
46 | public static final String GLASS_SCOPE = "https://www.googleapis.com/auth/glass.timeline "
47 | + "https://www.googleapis.com/auth/glass.location "
48 | + "https://www.googleapis.com/auth/userinfo.profile";
49 | private static final Logger LOG = Logger.getLogger(AuthUtil.class.getSimpleName());
50 |
51 | /**
52 | * Creates and returns a new {@link AuthorizationCodeFlow} for this app.
53 | */
54 | public static AuthorizationCodeFlow newAuthorizationCodeFlow() throws IOException {
55 | URL resource = AuthUtil.class.getResource("/oauth.properties");
56 | File propertiesFile = new File("./src/main/resources/oauth.properties");
57 | try {
58 | propertiesFile = new File(resource.toURI());
59 | //LOG.info("Able to find oauth properties from file.");
60 | } catch (URISyntaxException e) {
61 | LOG.info(e.toString());
62 | LOG.info("Using default source path.");
63 | }
64 | FileInputStream authPropertiesStream = new FileInputStream(propertiesFile);
65 | Properties authProperties = new Properties();
66 | authProperties.load(authPropertiesStream);
67 |
68 | String clientId = authProperties.getProperty("client_id");
69 | String clientSecret = authProperties.getProperty("client_secret");
70 |
71 | return new GoogleAuthorizationCodeFlow.Builder(new NetHttpTransport(), new JacksonFactory(),
72 | clientId, clientSecret, Collections.singleton(GLASS_SCOPE)).setAccessType("offline")
73 | .setCredentialStore(store).build();
74 | }
75 |
76 | /**
77 | * Get the current user's ID from the session
78 | *
79 | * @return string user id or null if no one is logged in
80 | */
81 | public static String getUserId(HttpServletRequest request) {
82 | HttpSession session = request.getSession();
83 | return (String) session.getAttribute("userId");
84 | }
85 |
86 | public static void setUserId(HttpServletRequest request, String userId) {
87 | HttpSession session = request.getSession();
88 | session.setAttribute("userId", userId);
89 | }
90 |
91 | public static void clearUserId(HttpServletRequest request) throws IOException {
92 | // Delete the credential in the credential store
93 | String userId = getUserId(request);
94 | store.delete(userId, getCredential(userId));
95 |
96 | // Remove their ID from the local session
97 | request.getSession().removeAttribute("userId");
98 | }
99 |
100 | public static Credential getCredential(String userId) throws IOException {
101 | if (userId == null) {
102 | return null;
103 | } else {
104 | return AuthUtil.newAuthorizationCodeFlow().loadCredential(userId);
105 | }
106 | }
107 |
108 | public static Credential getCredential(HttpServletRequest req) throws IOException {
109 | return AuthUtil.newAuthorizationCodeFlow().loadCredential(getUserId(req));
110 | }
111 |
112 | public static List getAllUserIds() {
113 | return store.listAllUsers();
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/com/google/glassware/ListableMemoryCredentialStore.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.google.glassware;
17 |
18 | import com.google.api.client.auth.oauth2.Credential;
19 | import com.google.api.client.auth.oauth2.CredentialStore;
20 |
21 |
22 | import java.util.*;
23 | import java.util.concurrent.locks.Lock;
24 | import java.util.concurrent.locks.ReentrantLock;
25 |
26 | /**
27 | * A new credential store. It's exactly the same as
28 | * com.google.api.client.auth.oauth2.MemoryCredentialStore except it
29 | * has the added ability to list all of the users.
30 | *
31 | * @author Jenny Murphy - http://google.com/+JennyMurphy
32 | */
33 | public class ListableMemoryCredentialStore implements CredentialStore {
34 |
35 | /**
36 | * Lock on access to the store.
37 | */
38 | private final Lock lock = new ReentrantLock();
39 |
40 | /**
41 | * Store of memory persisted credentials, indexed by userId.
42 | */
43 | private final Map store =
44 | new HashMap();
45 |
46 | public void store(String userId, Credential credential) {
47 | lock.lock();
48 | try {
49 | MemoryPersistedCredential item = store.get(userId);
50 | if (item == null) {
51 | item = new MemoryPersistedCredential();
52 | store.put(userId, item);
53 | }
54 | item.store(credential);
55 | } finally {
56 | lock.unlock();
57 | }
58 | }
59 |
60 | public void delete(String userId, Credential credential) {
61 | lock.lock();
62 | try {
63 | store.remove(userId);
64 | } finally {
65 | lock.unlock();
66 | }
67 | }
68 |
69 | public boolean load(String userId, Credential credential) {
70 | lock.lock();
71 | try {
72 | MemoryPersistedCredential item = store.get(userId);
73 | if (item != null) {
74 | item.load(credential);
75 | }
76 | return item != null;
77 | } finally {
78 | lock.unlock();
79 | }
80 | }
81 |
82 | public List listAllUsers() {
83 | List allUsers = new ArrayList();
84 | // Is that a 47 character long generic for one line of behavior? Yes, yes it is.
85 | for (Iterator> iterator = store.entrySet()
86 | .iterator();
87 | iterator.hasNext(); ) {
88 | allUsers.add(iterator.next().getKey());
89 | }
90 | return allUsers;
91 | }
92 |
93 | class MemoryPersistedCredential {
94 |
95 | /**
96 | * Access token or {@code null} for none.
97 | */
98 | private String accessToken;
99 |
100 | /**
101 | * Refresh token {@code null} for none.
102 | */
103 | private String refreshToken;
104 |
105 | /**
106 | * Expiration time in milliseconds {@code null} for none.
107 | */
108 | private Long expirationTimeMillis;
109 |
110 | /**
111 | * Store information from the credential.
112 | *
113 | * @param credential credential whose {@link Credential#getAccessToken access token},
114 | * {@link Credential#getRefreshToken refresh token}, and
115 | * {@link Credential#getExpirationTimeMilliseconds expiration time} need to be stored
116 | */
117 | void store(Credential credential) {
118 | accessToken = credential.getAccessToken();
119 | refreshToken = credential.getRefreshToken();
120 | expirationTimeMillis = credential.getExpirationTimeMilliseconds();
121 | }
122 |
123 | /**
124 | * Load information into the credential.
125 | *
126 | * @param credential credential whose {@link Credential#setAccessToken access token},
127 | * {@link Credential#setRefreshToken refresh token}, and
128 | * {@link Credential#setExpirationTimeMilliseconds expiration time} need to be set if the
129 | * credential already exists in storage
130 | */
131 | void load(Credential credential) {
132 | credential.setAccessToken(accessToken);
133 | credential.setRefreshToken(refreshToken);
134 | credential.setExpirationTimeMilliseconds(expirationTimeMillis);
135 | }
136 | }
137 | }
--------------------------------------------------------------------------------
/src/main/java/com/google/glassware/MainServlet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package com.google.glassware;
17 |
18 | import com.google.api.client.auth.oauth2.Credential;
19 | import com.google.api.client.googleapis.batch.BatchRequest;
20 | import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
21 | import com.google.api.client.googleapis.json.GoogleJsonError;
22 | import com.google.api.client.googleapis.json.GoogleJsonResponseException;
23 | import com.google.api.client.http.HttpHeaders;
24 | import com.google.api.services.mirror.model.Command;
25 | import com.google.api.services.mirror.model.Contact;
26 | import com.google.api.services.mirror.model.MenuItem;
27 | import com.google.api.services.mirror.model.MenuValue;
28 | import com.google.api.services.mirror.model.NotificationConfig;
29 | import com.google.api.services.mirror.model.TimelineItem;
30 | import com.google.common.collect.Lists;
31 |
32 | import java.io.IOException;
33 | import java.net.URL;
34 | import java.util.ArrayList;
35 | import java.util.List;
36 | import java.util.logging.Logger;
37 |
38 | import javax.servlet.http.HttpServlet;
39 | import javax.servlet.http.HttpServletRequest;
40 | import javax.servlet.http.HttpServletResponse;
41 |
42 | /**
43 | * Handles POST requests from index.jsp
44 | *
45 | * @author Jenny Murphy - http://google.com/+JennyMurphy
46 | */
47 | public class MainServlet extends HttpServlet {
48 |
49 | /**
50 | * Private class to process batch request results.
51 | *
52 | * For more information, see
53 | * https://code.google.com/p/google-api-java-client/wiki/Batch.
54 | */
55 | private final class BatchCallback extends JsonBatchCallback {
56 | private int success = 0;
57 | private int failure = 0;
58 |
59 | @Override
60 | public void onSuccess(TimelineItem item, HttpHeaders headers) throws IOException {
61 | ++success;
62 | }
63 |
64 | @Override
65 | public void onFailure(GoogleJsonError error, HttpHeaders headers) throws IOException {
66 | ++failure;
67 | LOG.info("Failed to insert item: " + error.getMessage());
68 | }
69 | }
70 |
71 | private static final Logger LOG = Logger.getLogger(MainServlet.class.getSimpleName());
72 | public static final String CONTACT_ID = "com.google.glassware.contact.java-quick-start";
73 | public static final String CONTACT_NAME = "Java Quick Start";
74 |
75 | private static final String PAGINATED_HTML =
76 | ""
77 | + "
Did you know...?
"
78 | + "
Cats are solar-powered. The time they spend napping in "
79 | + "direct sunlight is necessary to regenerate their internal batteries. Cats that do not "
80 | + "receive sufficient charge may exhibit the following symptoms: lethargy, "
81 | + "irritability, and disdainful glares. Cats will reactivate on their own automatically "
82 | + "after a complete charge cycle; it is recommended that they be left undisturbed during "
83 | + "this process to maximize your enjoyment of your cat.
"
84 | + "For more cat maintenance tips, tap to view the website!
"
85 | + "";
86 |
87 | /**
88 | * Do stuff when buttons on index.jsp are clicked
89 | */
90 | @Override
91 | protected void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException {
92 |
93 | String userId = AuthUtil.getUserId(req);
94 | Credential credential = AuthUtil.newAuthorizationCodeFlow().loadCredential(userId);
95 | String message = "";
96 |
97 | if (req.getParameter("operation").equals("insertSubscription")) {
98 |
99 | // subscribe (only works deployed to production)
100 | try {
101 | MirrorClient.insertSubscription(credential, WebUtil.buildUrl(req, "/notify"), userId,
102 | req.getParameter("collection"));
103 | message = "Application is now subscribed to updates.";
104 | } catch (GoogleJsonResponseException e) {
105 | LOG.warning("Could not subscribe " + WebUtil.buildUrl(req, "/notify") + " because "
106 | + e.getDetails().toPrettyString());
107 | message = "Failed to subscribe. Check your log for details";
108 | }
109 |
110 | } else if (req.getParameter("operation").equals("deleteSubscription")) {
111 |
112 | // subscribe (only works deployed to production)
113 | MirrorClient.deleteSubscription(credential, req.getParameter("subscriptionId"));
114 |
115 | message = "Application has been unsubscribed.";
116 |
117 | } else if (req.getParameter("operation").equals("insertItem")) {
118 | LOG.fine("Inserting Timeline Item");
119 | TimelineItem timelineItem = new TimelineItem();
120 |
121 | if (req.getParameter("message") != null) {
122 | timelineItem.setText(req.getParameter("message"));
123 | }
124 |
125 | // Triggers an audible tone when the timeline item is received
126 | timelineItem.setNotification(new NotificationConfig().setLevel("DEFAULT"));
127 |
128 | if (req.getParameter("imageUrl") != null) {
129 | // Attach an image, if we have one
130 | URL url = new URL(req.getParameter("imageUrl"));
131 | String contentType = req.getParameter("contentType");
132 | MirrorClient.insertTimelineItem(credential, timelineItem, contentType, url.openStream());
133 | } else {
134 | MirrorClient.insertTimelineItem(credential, timelineItem);
135 | }
136 |
137 | message = "A timeline item has been inserted.";
138 |
139 | } else if (req.getParameter("operation").equals("insertPaginatedItem")) {
140 | LOG.fine("Inserting Timeline Item");
141 | TimelineItem timelineItem = new TimelineItem();
142 | timelineItem.setHtml(PAGINATED_HTML);
143 |
144 | List