package de.fhb.autobday.manager.connector.google;
import com.google.gdata.client.contacts.ContactsService;
import com.google.gdata.data.contacts.Gender.Value;
import com.google.gdata.data.contacts.*;
import com.google.gdata.data.extensions.Email;
import com.google.gdata.util.ServiceException;
import de.fhb.autobday.commons.CipherHelper;
import de.fhb.autobday.commons.GoogleBirthdayConverter;
import de.fhb.autobday.commons.PropertyLoader;
import de.fhb.autobday.dao.AbdAccountFacade;
import de.fhb.autobday.dao.AbdContactFacade;
import de.fhb.autobday.dao.AbdGroupFacade;
import de.fhb.autobday.dao.AbdGroupToContactFacade;
import de.fhb.autobday.data.AbdAccount;
import de.fhb.autobday.data.AbdContact;
import de.fhb.autobday.data.AbdGroup;
import de.fhb.autobday.data.AbdGroupToContact;
import de.fhb.autobday.exception.commons.CanNotConvetGoogleBirthdayException;
import de.fhb.autobday.exception.commons.CouldNotDecryptException;
import de.fhb.autobday.exception.commons.CouldNotLoadMasterPasswordException;
import de.fhb.autobday.exception.connector.ConnectorCouldNotLoginException;
import de.fhb.autobday.exception.connector.ConnectorInvalidAccountException;
import de.fhb.autobday.exception.connector.ConnectorNoConnectionException;
import de.fhb.autobday.exception.connector.ConnectorRequestFailedException;
import de.fhb.autobday.manager.LoggerInterceptor;
import java.io.IOException;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
/**
* class to import the contact information and map the contacts to us contacts
* write the contact information in the database
*
* variablename if the variable start with abd this is an Auto-B-Day model
*
* @author Tino Reuschel mail: reuschel@fh-brandenburg.de
*/
@Stateless
@Local
@Interceptors(LoggerInterceptor.class)
public class GoogleImporter implements GoogleImporterLocal {
private final static Logger LOGGER = Logger.getLogger(GoogleImporter.class.getName());
protected boolean connectionEtablished;
protected AbdAccount accdata;
protected ContactsService myService;
@EJB
protected AbdContactFacade contactDAO;
@EJB
protected AbdGroupFacade groupDAO;
@EJB
protected AbdGroupToContactFacade groupToContactDAO;
@EJB
protected AbdAccountFacade accountDAO;
private PropertyLoader propLoader;
private List<String> errorStack = new ArrayList<String>();
public GoogleImporter() {
connectionEtablished = false;
accdata = null;
myService = null;
propLoader = new PropertyLoader();
}
/**
* {@inheritDoc}
*
* @param data
* @throws CouldNotDecryptException
* @throws CouldNotLoadMasterPasswordException
* @see
* de.fhb.autobday.manager.connector.AImporter#getConnection(de.fhb.autobday.data.AbdAccount)
* create connection to google contact api
*/
@Override
public void getConnection(AbdAccount data)
throws ConnectorCouldNotLoginException,
ConnectorInvalidAccountException, CouldNotDecryptException, CouldNotLoadMasterPasswordException {
String password = "";
Properties masterPassword;
connectionEtablished = false;
LOGGER.log(Level.INFO, "Account: {0}", data);
if (data == null) {
throw new ConnectorInvalidAccountException();
}
accdata = data;
// testausgabe
LOGGER.log(Level.INFO, "Username: {0}", accdata.getUsername());
LOGGER.log(Level.INFO, "Passwort: {0}", accdata.getPasswort());
//load master password
try {
masterPassword = propLoader.loadSystemProperty("/SystemCipherPassword.properties");
password = CipherHelper.decipher(accdata.getPasswort(), masterPassword.getProperty("master"));
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "File can´t read!");
throw new CouldNotLoadMasterPasswordException("File can´t read!");
} catch (InvalidKeyException e) {
LOGGER.log(Level.SEVERE, "Key not valid to decrypt Password");
throw new CouldNotDecryptException("Key not valid");
} catch (NoSuchAlgorithmException e) {
LOGGER.log(Level.SEVERE, "Algorithm not known");
throw new CouldNotDecryptException("Algorithm not known");
} catch (NoSuchPaddingException e) {
LOGGER.log(Level.SEVERE, "Padding not possible");
throw new CouldNotDecryptException("Padding not possible");
} catch (IllegalBlockSizeException e) {
LOGGER.log(Level.SEVERE, "Blocksize not valid");
throw new CouldNotDecryptException("Blocksize not valid");
} catch (BadPaddingException e) {
LOGGER.log(Level.SEVERE, "Padding invalid");
throw new CouldNotDecryptException("Padding invalid");
}
// connect to google
try {
myService = new ContactsService("BDayReminder");
myService.setUserCredentials(accdata.getUsername(),
password);
} catch (ServiceException ex) {
LOGGER.log(Level.SEVERE, null, ex.getMessage());
throw new ConnectorCouldNotLoginException(
"Importer cant connect to the account!");
}
connectionEtablished = true;
}
/**
* {@inheritDoc}
*
* @return errorStack
* @see de.fhb.autobday.manager.connector.AImporter#importContacts()
*/
@Override
public List<String> importContacts() throws ConnectorNoConnectionException, ConnectorRequestFailedException {
errorStack = new ArrayList<String>();
// if we have a connection and a valid accounddata then import the
// contacts and groups
// else throw an exception
if (connectionEtablished && accdata != null) {
accountDAO.flush();
updateGroups();
accountDAO.edit(accdata);
accountDAO.refresh(accdata);
updateContacts();
} else {
throw new ConnectorNoConnectionException("Connection to Google failed");
}
return errorStack;
}
/**
* Methode that update the Contact of an Account
*/
protected void updateContacts() throws ConnectorRequestFailedException{
AbdContact abdContact, abdContactInDB;
List<ContactEntry> contacts = getAllContacts();
int counter = 0;
LOGGER.log(Level.INFO, "Updating Contacts!");
LOGGER.log(Level.INFO, "{0} Contacts in queue!", contacts.size());
for (ContactEntry contactEntry : contacts) {
counter++;
abdContact = mapGContactToContact(contactEntry);
if (abdContact != null) {
LOGGER.log(Level.INFO, "Mapped Contact {0}: {1}", new Object[]{counter, abdContact});
abdContactInDB = contactDAO.find(abdContact.getId());
if (abdContactInDB == null) {
LOGGER.log(Level.INFO, "Adding Contact to db!");
contactDAO.create(abdContact);
contactDAO.flush();
} else {
LOGGER.log(Level.INFO, "Contact already in db: {0}", abdContactInDB);
abdContact.setAbdGroupToContactCollection(abdContactInDB.getAbdGroupToContactCollection());
if (abdContact.getUpdated().after(abdContactInDB.getUpdated())) {
LOGGER.log(Level.INFO, "Updating Contact in db!");
contactDAO.edit(abdContact);
contactDAO.flush();
}
}
contactDAO.flush();
updateMembership(abdContact, contactEntry);
} else {
LOGGER.log(Level.INFO, "Failed to map Contact {0}!", counter);
}
}
}
/**
* Method that update the Groups of an Account
*/
protected void updateGroups() throws ConnectorRequestFailedException{
AbdGroup abdGroup;
AbdGroup abdGroupOld;
List<ContactGroupEntry> groups = getAllGroups();
List<AbdGroup> abdGroups = new ArrayList<AbdGroup>(
accdata.getAbdGroupCollection());
List<Integer> toRemove = new ArrayList<Integer>();
boolean foundMatch = false;
for (ContactGroupEntry contactGroupEntry : groups) {
abdGroup = mapGGroupToGroup(contactGroupEntry);
LOGGER.log(Level.INFO, "Found GroupID: {0} Name: {1}", new Object[]{abdGroup, abdGroup.getName()});
// iterare over old groups
foundMatch = false;
for (int i = 0; i < abdGroups.size(); i++) {
abdGroupOld = abdGroups.get(i);
// if new group == old group
if (abdGroup.getId().equals(abdGroupOld.getId())) {
LOGGER.log(Level.INFO, "Group already in DB!");
foundMatch = true;
// and if new group newer than the old group
if (abdGroup.getUpdated().after(abdGroupOld.getUpdated())) {
LOGGER.log(Level.INFO, "Updating Group!");
groupDAO.edit(abdGroup);
groupDAO.flush();
abdGroups.remove(i);
abdGroups.add(i, abdGroup);
}
}
}
if (!foundMatch) {
LOGGER.log(Level.INFO, "Creating new Group!");
abdGroups.add(abdGroup);
}
}
for (AbdGroup abdGroupInDB : abdGroups) {
foundMatch = false;
for (ContactGroupEntry groupEntry : groups) {
if (abdGroupInDB.getId().equals(groupEntry.getId())) {
foundMatch = true;
}
}
if (!foundMatch) {
toRemove.add(0, abdGroups.indexOf(abdGroupInDB));
}
}
for (Integer index : toRemove) {
groupDAO.remove(abdGroups.get(index.intValue()));
abdGroups.remove(index.intValue());
}
accdata.setAbdGroupCollection(abdGroups);
}
/**
* methode that update the relationship between contact and group
*
* @param abdContact
* @param contactEntry
*/
public void updateMembership(AbdContact abdContact, ContactEntry contactEntry) {
List<GroupMembershipInfo> groupMembershipInfos = contactEntry.getGroupMembershipInfos();
List<AbdGroupToContact> abdMemberships = new ArrayList<AbdGroupToContact>(abdContact.getAbdGroupToContactCollection());
List<Integer> toRemove = new ArrayList<Integer>();
AbdGroupToContact abdMembership;
AbdGroup abdGroup;
boolean match = false;
for (GroupMembershipInfo groupMembershipInfo : groupMembershipInfos) {
match = false;
for (AbdGroupToContact abdGroupToContact : abdMemberships) {
if (abdGroupToContact.getAbdGroup().getId().equals(groupMembershipInfo.getHref())) {
match = true;
}
}
if (!match) {
abdGroup = groupDAO.find(groupMembershipInfo.getHref());
abdMembership = new AbdGroupToContact(groupMembershipInfo.getHref(), abdContact.getId());
abdMembership.setAbdGroup(abdGroup);
abdMembership.setAbdContact(abdContact);
abdMemberships.add(abdMembership);
}
}
for (AbdGroupToContact abdGroupToContact : abdMemberships) {
match = false;
for (GroupMembershipInfo groupMembershipInfo : groupMembershipInfos) {
if (abdGroupToContact.getAbdGroup().getId().equals(groupMembershipInfo.getHref())) {
match = true;
}
}
if (!match) {
toRemove.add(0, abdMemberships.indexOf(abdGroupToContact));
}
}
groupToContactDAO.flush();
for (Integer index : toRemove) {
LOGGER.log(Level.INFO, "remove {0}", index.intValue());
abdMembership = abdMemberships.get(index.intValue());
if (groupDAO.find(abdMembership.getAbdGroup().getId()) != null) {
groupToContactDAO.remove(abdMemberships.get(index.intValue()));
}
abdMemberships.remove(index.intValue());
}
match = false;
for (AbdGroupToContact abdGroupToContact : abdMemberships) {
if (abdGroupToContact.getActive()) {
match = true;
}
}
if (!match) {
if (abdMemberships.size()>0){
abdMemberships.get(0).setActive(true);
groupToContactDAO.edit(abdMemberships.get(0));
groupToContactDAO.flush();
}
}
abdContact.setAbdGroupToContactCollection(abdMemberships);
contactDAO.edit(abdContact);
}
/**
* get all groups from google from the connected account
*
* if dont get information from google return null else a list of Google
* ContactGroupEntrys
*
*
* @return List<ContactGroupEntry>
*/
protected List<ContactGroupEntry> getAllGroups() throws ConnectorRequestFailedException {
URL feedUrl;
try {
// url to get all groups
feedUrl = new URL(
"https://www.google.com/m8/feeds/groups/default/full?max-results=500");
ContactGroupFeed resultFeed = myService.getFeed(feedUrl,
ContactGroupFeed.class);
if (resultFeed == null) {
return null;
}
return resultFeed.getEntries();
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Fail to get Groups from Google");
throw new ConnectorRequestFailedException("Fail to get Groups");
} catch (ServiceException ex) {
LOGGER.log(Level.SEVERE, "Fail to get Groups from Google");
throw new ConnectorRequestFailedException("Fail to get Groups");
}
}
/**
* get all contacts from the connected acoount
*
* if dont get information from google return null else a list of Google
* ContactEntrys
*
* @return List<ContactEntry>
*/
protected List<ContactEntry> getAllContacts() throws ConnectorRequestFailedException{
URL feedUrl;
try {
feedUrl = new URL(
"https://www.google.com/m8/feeds/contacts/default/full?max-results=500");
ContactFeed resultFeed = myService.getFeed(feedUrl,
ContactFeed.class);
if (resultFeed == null) {
return null;
}
return resultFeed.getEntries();
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Fail to get Groups from Google");
throw new ConnectorRequestFailedException("Fail to get Contacts");
} catch (ServiceException ex) {
LOGGER.log(Level.SEVERE, "Fail to get Groups from Google");
throw new ConnectorRequestFailedException("Fail to get Contacts");
}
}
/**
* methode to map a google contact to a auto-b-day contact
*
* @param contactEntry
* @return AbdContact
*/
protected AbdContact mapGContactToContact(ContactEntry contactEntry) {
AbdContact abdContact;
String firstname;
String name;
Date birthday;
String mailadress;
String id;
Date updated;
abdContact = new AbdContact();
LOGGER.log(Level.INFO, "-------------------------------------------------");
abdContact.setHashid("12");
id = contactEntry.getId();
LOGGER.log(Level.INFO, "ID: {0}", id);
abdContact.setId(id);
firstname = getGContactFirstname(contactEntry);
LOGGER.log(Level.INFO, "Firstname: {0}", firstname);
if (!firstname.equals("")) {
abdContact.setFirstname(firstname);
} else {
errorStack.add("Skipping Contact " + abdContact.getFirstname() + " " + abdContact.getName() + ": No Firstname");
LOGGER.log(Level.SEVERE, "Skipping current Contact: No Firstname");
return null;
}
name = getGContactFamilyname(contactEntry);
LOGGER.log(Level.INFO, "Name: {0}", name);
if (!name.equals("")) {
abdContact.setName(name);
} else {
errorStack.add("Skipping Contact " + abdContact.getFirstname() + " " + abdContact.getName() + ": No Name");
LOGGER.log(Level.SEVERE, "Skipping current Contact: No Name");
return null;
}
birthday = getGContactBirthday(contactEntry);
LOGGER.log(Level.INFO, "birthday: {0}", birthday);
if (birthday != null) {
abdContact.setBday(birthday);
} else {
errorStack.add("Skipping Contact " + abdContact.getFirstname() + " " + abdContact.getName() + ": No Bday");
LOGGER.log(Level.SEVERE, "Skipping current Contact: No Bday");
return null;
}
if (!contactEntry.getEmailAddresses().isEmpty()) {
mailadress = getGContactFirstMailAdress(contactEntry);
abdContact.setMail(mailadress);
} else {
errorStack.add("Skipping Contact " + abdContact.getFirstname() + " " + abdContact.getName() + ": No Mail");
LOGGER.log(Level.SEVERE, "Skipping current Contact: No Mail");
return null;
}
try {
if (contactEntry.getGender().getValue() == Value.FEMALE) {
abdContact.setSex('w');
} else {
abdContact.setSex('m');
}
} catch (NullPointerException ex) {
abdContact.setSex(null);
}
updated = new Date(contactEntry.getUpdated().getValue());
abdContact.setUpdated(updated);
abdContact.setAbdGroupToContactCollection(new ArrayList<AbdGroupToContact>());
return abdContact;
}
/**
* Method that map a GoogleGroup to a Auto-B-Day-Group
*
* @param contactGroupEntry
* @return AbdGroup
*/
protected AbdGroup mapGGroupToGroup(ContactGroupEntry contactGroupEntry) {
AbdGroup abdGroupEntry;
String template = "Herzlichen Glückwunsch zum Geburtstag ${firstname}.";
abdGroupEntry = new AbdGroup();
abdGroupEntry.setId(contactGroupEntry.getId());
abdGroupEntry.setName(getGroupName(contactGroupEntry));
abdGroupEntry.setAccount(accdata);
abdGroupEntry.setActive(true);
abdGroupEntry.setTemplate(template);
abdGroupEntry.setUpdated(new Date(contactGroupEntry.getUpdated().getValue()));
return abdGroupEntry;
}
/**
* methode that return the firstname of a given contact
*
* @param contactEntry
*
* @return String
*/
protected String getGContactFirstname(ContactEntry contactEntry) {
String firstname = "";
try {
firstname = contactEntry.getName().getGivenName().getValue();
} catch (NullPointerException ex) {
}
return firstname;
}
/**
* methode that return the familyname of a given Contact
*
* @param contactEntry
*
* @return String
*/
protected String getGContactFamilyname(ContactEntry contactEntry) {
String familyname = "";
try {
familyname = contactEntry.getName().getFamilyName().getValue();
} catch (NullPointerException ex) {
}
return familyname;
}
/**
* methode that return the birthday of a given Contact
*
* @param contactEntry
*
* @return Date
*/
protected Date getGContactBirthday(ContactEntry contactEntry) {
String gContactBirthday;
Date bday = null;
try {
gContactBirthday = contactEntry.getBirthday().getValue();
bday = GoogleBirthdayConverter.convertBirthday(gContactBirthday);
} catch (CanNotConvetGoogleBirthdayException ex) {
} catch (NullPointerException ex) {
}
return bday;
}
/**
* Methode that return a mailadress of a given Contact
*
* @param contactEntry
*
* @return String
*/
protected String getGContactFirstMailAdress(ContactEntry contactEntry) {
List<Email> mailadresses;
String mailadress;
mailadresses = contactEntry.getEmailAddresses();
if (mailadresses.size() > 0) {
mailadress = mailadresses.get(0).getAddress();
return mailadress;
}
return "";
}
/**
* Methode that return the Groupname from a GoogleGroup
*
* @param contactGroupEntry
* @return String
*/
protected String getGroupName(ContactGroupEntry contactGroupEntry) {
String groupName = "";
try {
groupName = contactGroupEntry.getTitle().getPlainText();
} catch (NullPointerException ex) {
}
return groupName;
}
/**
* {@inheritDoc}
*
* @see de.fhb.autobday.manager.connector.AImporter#isConnectionEtablished()
*/
@Override
public boolean isConnectionEtablished() {
return connectionEtablished;
}
public PropertyLoader getPropLoader() {
return propLoader;
}
public void setPropLoader(PropertyLoader propLoader) {
this.propLoader = propLoader;
}
}