Skip to main content

Google Groups Settings : an "how-to" solution without Google's Java API

I'm used to work with Google online services and my opinion is :
  • Google protocol is good (of course!) and I think that the direction which is taken to migrate to REST services is the good one.
  • the documentation is never up-to-date and often contains wrong code samples (which sometimes doesn't compile because it contains deprecated instruction calls or string values).
  • the Java API provides by Google is horrible. The support of Maven is still bad (it's better since of few months). It's confused between the provisioning API (GData library) and the Google Java Client API. Sometimes, you have to use the first one, sometimes the second.
  • the authentication methods are also confused. You have to choice between ClientLogin, AuthSub, OAuth1 and OAuth2 (and OpenID?) : what's the fuck? On OAuth, you have other choice to take because the authentication workflow is different if you application is on the web or embedded. This situation could be clearer and Google should refine its authentication politic. They should consider only authentication for administration apps (without code exchange and OAuth token cooking) and authentication for end-user apps.
So, I had some difficulties to work this the recent API for groups settings and I decided to share some piece of code. The idea of my code it NOT TO USE the Google Java Client API. I prefer to dialog directly with Google and to use the XStream lib to do that.

Here is my code to retrieve a group settings. It is not a code for an end-user apps (where you should use OAuth2 authentication). I use it for admin tasks :



public GoogleGroupConfiguration getConfiguration(String groupName) {

try {
String groupEmail = MY_GROUP_EMAIL;
URL url = new URL("https://www.googleapis.com/groups/v1/groups/" + groupEmail + "?key=MY_APP_KEY_OBTAINED_FROM_GOOGLE_CONSOLE_API&alt=json");
GoogleGroupConfiguration groupConfiguration = new GoogleGroupConfiguration();
HttpTransport transport = new NetHttpTransport();

// authenticate with ClientLogin
ClientLogin authenticator = new ClientLogin();
authenticator.username = MY_USERNAME;
authenticator.password = MY_PASSWORD;
authenticator.accountType = "HOSTED_OR_GOOGLE";
authenticator.authTokenType = "apps";
authenticator.transport = transport;
Response authenticate = authenticator.authenticate();
String authorizationHeaderValue = authenticate.getAuthorizationHeaderValue();

// make query request
HttpRequestFactory requestFactory = transport.createRequestFactory();
HttpRequest request = requestFactory.buildGetRequest(new GenericUrl(url.toString()));
request.getHeaders().setAuthorization(authorizationHeaderValue);
request.addParser(new JsonCParser(new JacksonFactory()));

// Make request and parse result
HttpResponse execute = request.execute();
String parseAsString = execute.parseAsString();
System.out.println(parseAsString);
JettisonMappedXmlDriver hierarchicalStreamDriver = new JettisonMappedXmlDriver();
XStream xstream = new XStream(hierarchicalStreamDriver);
parseAsString = "{\"" + GoogleGroupConfiguration.class.getName() + "\":" + parseAsString + "}";
xstream.fromXML(parseAsString, groupConfiguration);
return groupConfiguration;
} catch (Exception e) {
e.printStackTrace();
throw new GoogleAccessException(e);
}
}

public class GoogleGroupConfiguration {

public enum MessageDisplayFontEnum {
DEFAULT_FONT, FIXED_WIDTH_FONT
}

public enum MessageModerationLevelEnum {
MODERATE_ALL_MESSAGES, MODERATE_NEW_MEMBERS, MODERATE_NONE, MODERATE_NON_MEMBERS
}

public enum ReplyToEnum {
REPLY_TO_CUSTOM, REPLY_TO_IGNORE, REPLY_TO_LIST, REPLY_TO_MANAGERS, REPLY_TO_OWNER, REPLY_TO_SENDER
}

public enum WhoCanInviteEnum {
ALL_MANAGERS_CAN_INVITE, ALL_MEMBERS_CAN_INVITE
}

public enum WhoCanJoinEnum {
ALL_IN_DOMAIN_CAN_JOIN, ANYONE_CAN_JOIN, CAN_REQUEST_TO_JOIN, INVITED_CAN_JOIN
}

public enum WhoCanPostMessageEnum {
ALL_IN_DOMAIN_CAN_POST, ALL_MANAGERS_CAN_POST, ALL_MEMBERS_CAN_POST, ANYONE_CAN_POST, NONE_CAN_POST
}

public enum WhoCanViewGroupEnum {
ALL_IN_DOMAIN_CAN_VIEW, ALL_MANAGERS_CAN_VIEW, ALL_MEMBERS_CAN_VIEW, ANYONE_CAN_VIEW
}

public enum WhoCanViewMembershipEnum {
ALL_IN_DOMAIN_CAN_VIEW, ALL_MANAGERS_CAN_VIEW, ALL_MEMBERS_CAN_VIEW
}

private String kind;
private String email;
private String name;
private String description;
private WhoCanJoinEnum whoCanJoin;
private WhoCanViewMembershipEnum whoCanViewMembership;
private WhoCanViewGroupEnum whoCanViewGroup;
private WhoCanInviteEnum whoCanInvite;
private boolean allowExternalMembers;
private WhoCanPostMessageEnum whoCanPostMessage;
private boolean allowWebPosting;
private long maxMessageBytes;
private boolean isArchived;
private boolean archiveOnly;
private MessageModerationLevelEnum messageModerationLevel;
private ReplyToEnum replyTo;
private String customReplyTo;
private boolean sendMessageDenyNotification;
private String defaultMessageDenyNotificationText;
private boolean showInGroupDirectory;
private boolean allowGoogleCommunication;
private boolean membersCanPostAsTheGroup;
private MessageDisplayFontEnum messageDisplayFont;

public void setArchiveOnly(boolean isArchiveOnly) {
if (isArchiveOnly) {
this.whoCanPostMessage = WhoCanPostMessageEnum.NONE_CAN_POST;
}
if (this.archiveOnly && !isArchiveOnly) {
this.whoCanPostMessage = WhoCanPostMessageEnum.ALL_MANAGERS_CAN_POST;
}
this.archiveOnly = isArchiveOnly;
}

public void setWhoCanPostMessage(WhoCanPostMessageEnum newWhoCanPostMessage) {
if (newWhoCanPostMessage.equals(WhoCanPostMessageEnum.ALL_MANAGERS_CAN_POST)) {
this.messageModerationLevel = MessageModerationLevelEnum.MODERATE_NON_MEMBERS;
}
}

// ... add getters/setters

}



The idea is to get an auth token with the classic ClientLogin method. Then, I always put this token in each request header. Don't forget to add the API access key you can obtain from the Google console API. It allows you to access data you don't own (which is the case for administration batch processes). As you can see, I set alt=json into the request URL to get a json response. I created the GoogleGroupSettings class to map the Google response directly to an object through XStream.

If you already use AppsForYourDomain code, you can build requests without using the Clientlogin method. Create an AppsGroupService instance and work with GDataRequest.
I give you an example :



AppsGroupsService groupService = new AppsGroupsService(adminEmail, adminPassword, domain,"gdata-sample-AppsForYourDomain-AppsGroupService");
GDataRequest entryRequest = groupService.createEntryRequest(url);
entryRequest.execute();
InputStream inputStream = entryRequest.getResponseStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
for (int readBytes = inputStream.read(); readBytes >= 0; readBytes = inputStream.read())
outputStream.write(readBytes);
// Convert the contents of the output stream into a byte array
byte[] byteData = outputStream.toByteArray();
String parseAsString = new String(byteData);
parseAsString = "{\"" + GoogleGroupConfiguration.class.getName() + "\":" + parseAsString + "}";

// Parse result with XStream
JettisonMappedXmlDriver hierarchicalStreamDriver = new JettisonMappedXmlDriver();
XStream xstream = new XStream(hierarchicalStreamDriver);
xstream.fromXML(parseAsString, groupConfiguration);

// Close the streams
inputStream.close();
outputStream.close();


I hope this code will help you.


Comments

alazizonline said…
wao .......... Thanks For Sharing . keep up the god work

Khurram Shahzad
Alaziz Online
Richard said…
Thanks for sharing, how to update the Group Settings using the same approach?
Ram said…
Here, you are using a class called ClientLogin. Is it part of Google Java API or our own written class?

Popular posts from this blog

DCcduino usb drivers (CH340 / CH341 chipset)

I've just received my first arduino platform. It's a DCcduino board (a clone of Arduino Uno). As I had some difficulties to have it recognised by my MacBook, I decided to share its drivers. This card has a CH340 USB-to-serial chip. You can find drivers for this chip on the web site of the chinese manufacturer, here :

http://www.wch.cn/downloads.php?name=pro&proid=5

Or download it directly from my Google Drive. The archive contains drivers for Mac, Linux and Windows platforms.

https://drive.google.com/file/d/0B5okZr5AW4gaX2pZaWt6dVNaSFU/edit?usp=sharing

I hope this will help somebody.

UPDATE for Mac users with Yosemite :

Please, follow this extra instructions :
Install the CH340 driverRun the command in Terminal: sudo nvram boot-args="kext-dev-mode=1"Reboot

The great alternative to JRebel

I'm an old user and addict of JRebel. I started to use it on open source projects and in professional contexts. From the beginning, I've been convinced that the licensing mode was wrong because of its lifetime. Asking for license renewal each year is boring. So, I decided to look for FREE alternative solutions and finally I recently found one.

This solution is efficient for maven projects developed with Eclipse. It is base on :

Hotswap Agent project : http://hotswapagent.org/Dynamic Source Lookup plugin for Eclipse : https://github.com/ifedorenko/com.ifedorenko.m2e.sourcelookup
I tested it with Java 7 & Java 8. I work on web applications that run on Tomcat. I developed wih Spring (IoC), sometimes Hibernate and Vaadin



Hotswap Agent installation consists on the deployment of a patch for your JVM. You just have to download the corresponding patch here : https://github.com/dcevm/dcevm/releases Then, download the hotswap-agent.jar from here : https://github.com/HotswapProjects…

How to secure REST services exposed with Jersey (JAX-RS) using Spring Security

This is the challenge I had to perform. I have to open services to business partners and I want to secure them. I use a Java based application with Jersey API (JAX-RS).

The first thing to consider is : what kind of solution offers the best compromise between security and the effort I'll have to provide to maintain this solution?
After some discussions with developers and experts, the conclusion is : expose your services over https and use Basic authentication (Digest authentication and certificate based authentication are too complex for partners)

So, how to implement that? I delegate "https" to my Apache http servers. But I still need to handle authentication (and authorization of course). After long hours on Google, I understood that it is possible to manage security with Jersey by many many ways. Here is a short list :

Delegate simple authentication and authorization to your container (Tomcat) or to your frontend (Apache)Delegate authentication to your container or fro…