/*
* Copyright 2013 McEvoy Software Ltd.
*
* 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 com.bandstand.web;
import com.bandstand.domain.Musician;
import com.bandstand.domain.SessionManager;
import io.milton.annotations.AddressBooks;
import io.milton.annotations.ChildrenOf;
import io.milton.annotations.ContactData;
import io.milton.annotations.Get;
import io.milton.annotations.ModifiedDate;
import io.milton.annotations.PrincipalSearch;
import io.milton.annotations.PutChild;
import io.milton.annotations.ResourceController;
import io.milton.common.ModelAndView;
import io.milton.http.exceptions.BadRequestException;
import io.milton.principal.PrincipalSearchCriteria;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import net.sourceforge.cardme.engine.VCardEngine;
import net.sourceforge.cardme.io.VCardWriter;
import net.sourceforge.cardme.vcard.VCard;
import net.sourceforge.cardme.vcard.VCardImpl;
import net.sourceforge.cardme.vcard.features.EmailFeature;
import net.sourceforge.cardme.vcard.features.TelephoneFeature;
import net.sourceforge.cardme.vcard.types.BeginType;
import net.sourceforge.cardme.vcard.types.EmailType;
import net.sourceforge.cardme.vcard.types.EndType;
import net.sourceforge.cardme.vcard.types.FormattedNameType;
import net.sourceforge.cardme.vcard.types.NameType;
import net.sourceforge.cardme.vcard.types.TelephoneType;
import net.sourceforge.cardme.vcard.types.UIDType;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Junction;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* For accessing other musicians as contacts via carddav
*
* @author brad
*/
@ResourceController
public class ContactsController {
private static final Logger log = LoggerFactory.getLogger(ContactsController.class);
@ChildrenOf
public MusicianAddressBooksHome getAddressBookHome(Musician m) {
return new MusicianAddressBooksHome(m);
}
@ChildrenOf
@AddressBooks
public MusicianAddressBook getAddressBook(MusicianAddressBooksHome m) {
return new MusicianAddressBook(m.musician);
}
@ChildrenOf
public List<MusicianContact> getMusicianContacts(MusicianAddressBook addressBook) {
List<MusicianContact> list = new ArrayList<MusicianContact>();
for (Musician m : Musician.findAll(SessionManager.session())) {
list.add(new MusicianContact(m));
}
return list;
}
@PrincipalSearch
public List<MusicianContact> searchMusicianContacts(MusicianAddressBook addressBook, PrincipalSearchCriteria crit) {
if( crit.getCuType().equals(PrincipalSearchCriteria.CU_TYPE_INDIVIDUAL) ) {
Criteria c = SessionManager.session().createCriteria(MusicianContact.class);
Junction combine;
if( crit.getTest().equals(PrincipalSearchCriteria.TestType.ALL)) {
combine = Restrictions.disjunction();
} else {
combine = Restrictions.conjunction();
}
for( PrincipalSearchCriteria.SearchItem searchItem : crit.getSearchItems()) {
Criterion r = newCriterion(searchItem);
if( r != null ) {
combine.add(r);
}
}
c.add(combine);
}
return null;
}
private Criterion newCriterion(PrincipalSearchCriteria.SearchItem searchItem) {
switch(searchItem.getMatchType()) {
case CONTAINS:
return Restrictions.like(searchItem.getField(), "%" + searchItem.getValue() + "%");
case ENDSWITH:
return Restrictions.like(searchItem.getField(), "%" + searchItem.getValue() );
case EXACT:
return Restrictions.eq(searchItem.getField(), searchItem.getValue() );
case STARTSWITH:
return Restrictions.like(searchItem.getField(), searchItem.getValue() + "%");
}
return null;
}
@ContactData
@Get
public byte[] getContactData(MusicianContact c) {
Musician m = c.contact;
try {
VCardImpl vcard = new VCardImpl();
vcard.setBegin(new BeginType());
vcard.setID(m.getContactUid());
String uid = m.getContactUid();
if (uid == null || uid.length() == 0) {
uid = m.getName();
}
vcard.setUID(new UIDType(uid));
vcard.setFormattedName(new FormattedNameType(m.getGivenName() + " " + m.getSurName()));
vcard.setName(new NameType(m.getSurName(), m.getGivenName()));
if (!StringUtils.isBlank(m.getTelephonenumber())) {
vcard.addTelephoneNumber(new TelephoneType(m.getTelephonenumber()));
}
if (!StringUtils.isBlank(m.getMail())) {
vcard.addEmail(new EmailType(m.getMail()));
}
vcard.setEnd(new EndType());
VCardWriter writer = new VCardWriter();
writer.setVCard(vcard);
return writer.buildVCardString().getBytes("UTF-8");
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
@PutChild
public MusicianContact createMusicianContact(MusicianAddressBook abook, String newName, byte[] vcardData) throws BadRequestException {
Transaction tx = SessionManager.session().beginTransaction();
try {
VCardEngine cardEngine = new VCardEngine();
String vc = new String(vcardData);
System.out.println("---- contact ----");
System.out.println(vc);
System.out.println("-------");
VCard vcard = cardEngine.parse(vc);
Musician m = new Musician();
if (vcard.getUID() != null) {
m.setContactUid(vcard.getUID().getUID());
} else {
m.setContactUid(UUID.randomUUID().toString());
}
m.setName(newName);
m.setCreatedDate(new Date());
m.setGivenName(vcard.getName().getGivenName());
m.setSurName(vcard.getName().getFamilyName());
m.setModifiedDate(new Date());
{
Iterator<TelephoneFeature> it = vcard.getTelephoneNumbers();
while (it.hasNext()) {
m.setTelephonenumber(it.next().getTelephone());
}
}
{
Iterator<EmailFeature> itEmails = vcard.getEmails();
while (itEmails.hasNext()) {
m.setMail(itEmails.next().getEmail());
}
}
SessionManager.session().save(m);
SessionManager.session().flush();
tx.commit();
return new MusicianContact(m);
} catch (Exception e) {
tx.rollback();
log.error("exception uploading musician contact", e);
throw new BadRequestException(e.getMessage());
}
}
@PutChild
public MusicianContact updateMusicianContact(MusicianContact contact, byte[] vcardData) throws BadRequestException {
log.info("updateMusicianContact");
Transaction tx = SessionManager.session().beginTransaction();
try {
Musician m = contact.getMusician();
VCardEngine cardEngine = new VCardEngine();
String vc = new String(vcardData);
System.out.println("---- contact ----");
System.out.println(vc);
System.out.println("-------");
VCard vcard = cardEngine.parse(vc);
if (vcard.getUID() != null) {
m.setContactUid(vcard.getUID().getUID());
}
if (vcard.getName() != null) {
m.setGivenName(vcard.getName().getGivenName());
m.setSurName(vcard.getName().getFamilyName());
} else {
log.warn("No name feature in supplied vcard: " + vc);
}
m.setModifiedDate(new Date());
{
Iterator<TelephoneFeature> it = vcard.getTelephoneNumbers();
while (it.hasNext()) {
m.setTelephonenumber(it.next().getTelephone());
}
}
{
Iterator<EmailFeature> itEmails = vcard.getEmails();
while (itEmails.hasNext()) {
m.setMail(itEmails.next().getEmail());
}
}
m.setModifiedDate(new Date());
SessionManager.session().save(m);
SessionManager.session().flush();
tx.commit();
return contact;
} catch (Exception e) {
tx.rollback();
log.error("exception uploading musician contact", e);
throw new BadRequestException(e.getMessage());
}
}
@ModifiedDate
public Date getContactModDate(MusicianContact c) {
return c.getMusician().getModifiedDate();
}
@Get
public ModelAndView renderAddressBookPage(MusicianAddressBook addressBook) {
return new ModelAndView("addressBook", addressBook, "abook");
}
public class MusicianContact {
private final Musician contact;
public MusicianContact(Musician contact) {
this.contact = contact;
}
public String getId() {
return contact.getId() + "";
}
public String getName() {
return contact.getName();
}
public Musician getMusician() {
return contact;
}
}
public class MusicianAddressBooksHome {
private final Musician musician;
public MusicianAddressBooksHome(Musician musician) {
this.musician = musician;
}
public String getName() {
return "abooks";
}
}
public class MusicianAddressBook {
private final Musician musician;
public MusicianAddressBook(Musician musician) {
this.musician = musician;
}
public String getName() {
return "default";
}
}
}