View Javadoc

1   /*
2    * Copyright 2007 The International Moth Class Association (IMCA)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of 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,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.imca.model;
17  
18  import java.util.List;
19  import java.util.Locale;
20  import java.util.Random;
21  import java.util.Vector;
22  
23  import javax.mail.MessagingException;
24  import javax.mail.Transport;
25  import javax.mail.internet.AddressException;
26  import javax.mail.internet.InternetAddress;
27  import javax.mail.internet.MimeMessage;
28  import javax.persistence.EntityManager;
29  import javax.persistence.Query;
30  
31  import org.apache.commons.codec.binary.Base64;
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.w3c.dom.NodeList;
35  
36  import net.sf.imca.model.entities.AssociationDAO;
37  import net.sf.imca.model.entities.MembershipTypeEntity;
38  import net.sf.imca.model.entities.PersonEntity;
39  import net.sf.imca.model.entities.AddressEntity;
40  import net.sf.imca.model.entities.CommitteeMemberEntity;
41  import net.sf.imca.model.exceptions.DataCheckingException;
42  import net.sf.imca.model.exceptions.LogInException;
43  import net.sf.imca.model.exceptions.RegistrationException;
44  
45  import java.io.UnsupportedEncodingException;
46  import java.security.MessageDigest;
47  import java.security.NoSuchAlgorithmException;
48  
49  /**
50   * Business Object representing the properties, persistence and functionality of
51   * the IMCA domain object.
52   * 
53   * @author dougculnane
54   */
55  public class PersonBO {
56  
57      /**
58       * Apache Commons Logger specific to this class.
59       */
60      private Log log = LogFactory.getLog(PersonBO.class);
61  
62      /**
63       * Entity for persisting this Business Object.
64       */
65      private PersonEntity entity;
66  
67      public PersonBO(){}
68  
69      public PersonBO(EntityManager em, long id) {
70          this.setEntity(em.find(PersonEntity.class, id));
71      }
72  
73      public PersonBO(EntityManager em, String email) {
74          findEntity(em, email);
75      }
76      
77      @SuppressWarnings("unchecked")
78      public PersonBO(EntityManager em, String email, String password)
79              throws LogInException {
80  
81          
82          if (email == null || password == null) {
83              log.warn("Email or Password value is NULL");
84              throw new LogInException("Email or Password value is NULL");
85          }
86          if (email.trim().length() == 0) {
87              log.warn("Email value is empty.");
88              throw new LogInException("Email value is empty");
89          }
90          if (password.length() < 8) {
91              log.warn("Password too short.");
92              throw new LogInException("Password too short");
93          }
94          
95          try {
96              new InternetAddress(email);
97          } catch (AddressException e) {
98              log.warn("Invalid email address: " + email, e);
99              throw new LogInException("Email Address not valid.");
100         }
101         
102         Query query = em.createNamedQuery("findPersonByEmail");
103         query.setParameter("email", email);
104         List<PersonEntity> list = query.getResultList();
105 
106         PersonEntity dbPerson = new PersonEntity();
107 
108         if (list.size() == 1) {
109             dbPerson = list.get(0);
110         } else {
111             throw new LogInException("Email address not found.");
112         }
113 
114         try {
115             if (dbPerson.getPassword().equals(endcodePassword(password))) {
116                 setEntity(dbPerson);
117             } else if (dbPerson.getResetPassword() != null
118                     && dbPerson.getResetPassword().equals(password)) {
119                 setEntity(dbPerson);
120             } else {
121                 throw new LogInException("Email and password do not match.");
122             }
123         } catch (UnsupportedEncodingException e) {
124             log.error(e);
125             throw new LogInException("Error Encoding Password.");
126         } catch (NoSuchAlgorithmException e) {
127             log.error(e);
128             throw new LogInException("Error Encoding Password.");
129         }
130     }
131     
132     @SuppressWarnings("unchecked")
133     public PersonBO(EntityManager em, NodeList nodeList) {
134 
135         String xmlId = "";
136         String name = "";
137         String landcode = "";
138         String tel = "";
139         String mobile = "";
140         String url = "";
141         String email_username = "";
142         String email_domain = "";
143 
144         String address_street1 = "";
145         String address_street2 = "";
146         String address_city = "";
147         String address_area = "";
148         String address_postcode = "";
149         String address_country = "";
150 
151         for (int i = 0; i < nodeList.getLength(); i++) {
152             if ("id".equals(nodeList.item(i).getNodeName())) {
153                 xmlId = nodeList.item(i).getChildNodes().item(0).getNodeValue();
154             } else if ("name".equals(nodeList.item(i).getNodeName())) {
155                 name = nodeList.item(i).getChildNodes().item(0).getNodeValue();
156             } else if ("landcode".equals(nodeList.item(i).getNodeName())) {
157                 landcode = PersonBO.convertOldXmlCountryCodesToISO(
158                         nodeList.item(i).getChildNodes().item(0).getNodeValue());
159             } else if ("tel".equals(nodeList.item(i).getNodeName())) {
160                 if (nodeList.item(i).getChildNodes().item(0) != null) {
161                     tel = nodeList.item(i).getChildNodes().item(0)
162                             .getNodeValue();
163                 }
164             } else if ("mobile".equals(nodeList.item(i).getNodeName())) {
165                 mobile = nodeList.item(i).getChildNodes().item(0)
166                         .getNodeValue();
167             } else if ("url".equals(nodeList.item(i).getNodeName())) {
168                 url = nodeList.item(i).getChildNodes().item(0).getNodeValue();
169             } else if ("email".equals(nodeList.item(i).getNodeName())) {
170                 NodeList emailNodes = nodeList.item(i).getChildNodes();
171                 for (int j = 0; j < emailNodes.getLength(); j++) {
172                     if ("username".equals(emailNodes.item(j).getNodeName())) {
173                         email_username = emailNodes.item(j).getChildNodes()
174                                 .item(0).getNodeValue();
175                     } else if ("domain"
176                             .equals(emailNodes.item(j).getNodeName())) {
177                         email_domain = emailNodes.item(j).getChildNodes().item(
178                                 0).getNodeValue();
179                     }
180                 }
181 
182             } else if ("address".equals(nodeList.item(i).getNodeName())) {
183                 NodeList addressNodes = nodeList.item(i).getChildNodes();
184                 for (int j = 0; j < addressNodes.getLength(); j++) {
185                     if ("street1".equals(addressNodes.item(j).getNodeName())) {
186                         address_street1 = addressNodes.item(j).getChildNodes()
187                                 .item(0).getNodeValue();
188                     } else if ("street2".equals(addressNodes.item(j)
189                             .getNodeName())) {
190                         address_street2 = addressNodes.item(j).getChildNodes()
191                                 .item(0).getNodeValue();
192                     } else if ("city"
193                             .equals(addressNodes.item(j).getNodeName())) {
194                         address_city = addressNodes.item(j).getChildNodes()
195                                 .item(0).getNodeValue();
196                     } else if ("postcode".equals(addressNodes.item(j)
197                             .getNodeName())) {
198                         address_postcode = addressNodes.item(j).getChildNodes()
199                                 .item(0).getNodeValue();
200                     } else if ("area"
201                             .equals(addressNodes.item(j).getNodeName())) {
202                         address_area = addressNodes.item(j).getChildNodes()
203                                 .item(0).getNodeValue();
204                     } else if ("country".equals(addressNodes.item(j)
205                             .getNodeName())) {
206                         address_country = PersonBO.convertOldXmlCountryCodesToISO(
207                                 addressNodes.item(j).getChildNodes().item(0).getNodeValue());
208                     }
209                 }
210             }
211         }
212         setEntity(new PersonEntity());
213 
214         if (!"".equals(xmlId)) {
215             Query query = em.createNamedQuery("findPersonByXmlId");
216             query.setParameter("xmlId", xmlId);
217             List<PersonEntity> list = query.getResultList();
218 
219             if (list.size() == 0) {
220             } else {
221                 setEntity(list.get(0));
222             }
223         }
224 
225         int nameDivPosition = 0;
226         if (name.indexOf(" ") > 0) {
227             nameDivPosition = name.indexOf(" ");
228         }
229 
230         getEntity().setFirstName(name.substring(0, nameDivPosition));
231         getEntity().setLastName(name.substring(nameDivPosition).trim());
232         getEntity().setXmlId(xmlId);
233         getEntity().setMobile(mobile);
234         getEntity().setTel(tel);
235         getEntity().setUrl(url);
236         if (email_username.length() + email_domain.length() > 0) {
237             getEntity().setEmail(email_username + "@" + email_domain);
238         }
239         if (getEntity().getAddress() == null) {
240             getEntity().setAddress(new AddressEntity());
241         }
242         getEntity().getAddress().setStreet1(address_street1);
243         getEntity().getAddress().setStreet2(address_street2);
244         getEntity().getAddress().setCity(address_city);
245         getEntity().getAddress().setArea(address_area);
246         getEntity().getAddress().setPostCode(address_postcode);
247         
248         if ("".equals(address_country)) {
249             getEntity().getAddress().setCountryCode(landcode);
250         } else {
251             getEntity().getAddress().setCountryCode(address_country);
252         }
253         em.persist(getEntity());
254         em.persist(getEntity().getAddress());
255     }
256     
257     public PersonBO(PersonEntity personEntity) {
258         this.setEntity(personEntity);
259     }
260 
261     public boolean register(EntityManager em) 
262             throws RegistrationException, AddressException {
263         
264         if (findEntity(em, getEntity().getEmail())) {
265             throw new RegistrationException(
266                     "Email address already registered.");
267         }
268         em.persist(getEntity().getAddress());
269         em.persist(getEntity());
270         return true;
271     }
272 
273     /**
274      * Get the persistence entity.
275      *
276      * @return The persistence entity for this Business Object.
277      */
278     public PersonEntity getEntity() {
279         return entity;
280     }
281 
282     /**
283      * Set the persistence entity.
284      *
285      * @param entity The new persistence entity for this Business Object.
286      */
287     public void setEntity(PersonEntity entity) {
288         this.entity = entity;
289     }
290 
291     public void setPasswordEncodeAndSet(String plainTextPassword) 
292             throws UnsupportedEncodingException, NoSuchAlgorithmException, 
293             DataCheckingException {
294         
295         if (plainTextPassword.length() < 8) {
296             throw new DataCheckingException("Password too short.");
297         }
298         
299         getEntity().setPassword(endcodePassword(plainTextPassword));
300     }
301     
302     private String endcodePassword(String password)
303             throws UnsupportedEncodingException, NoSuchAlgorithmException {
304 
305         MessageDigest md = MessageDigest.getInstance("SHA");
306         md.update(password.getBytes("UTF-8"));
307         byte raw[] = md.digest();
308         Base64 base64 = new Base64();
309         String hash = new String(base64.encode(raw));
310         return hash;
311     }
312 
313     /**
314      * Send password by mail. TODO: Mailserver config from properties file.
315      * 
316      * @param em EntityManager for persistence.
317      * @param email user supplied email address.
318      * @throws MessagingException When problem occurs.
319      */
320     public void sendPassword(EntityManager em, InternetAddress email)
321             throws MessagingException, DataCheckingException {
322 
323         MimeMessage message = ImcaUtils.createEmailMessage();
324 
325         message.setRecipients(MimeMessage.RecipientType.TO,
326                 new InternetAddress[] { email });
327 
328         message.setSubject(ImcaUtils.getMessage(
329                 "PasswordReminderSubject", this.getLocale()),
330                 ImcaUtils.MAIL_ENCODING);
331         
332         message.setText(
333                 ImcaUtils.getMessage("YourPasswordIs", this.getLocale()) +
334                 " " + resetPassword(em, email), ImcaUtils.MAIL_ENCODING);
335 
336         Transport.send(message);
337     }
338 
339     public Locale getLocale() {
340         if (getEntity() == null) {
341             return Locale.ENGLISH;
342         }
343         return new Locale(getEntity().getLanguageCode(), getEntity().getAddress().getCountryCode());
344     }
345 
346     /**
347      * 
348      * @param em
349      * @param email
350      * @return
351      */
352     @SuppressWarnings("unchecked")
353     private String resetPassword(EntityManager em, InternetAddress email) 
354         throws DataCheckingException {
355 
356         Query query = em.createNamedQuery("findPersonByEmail");
357         query.setParameter("email", email.getAddress());
358         List<PersonEntity> list = query.getResultList();
359         StringBuffer buf = new StringBuffer();
360 
361         if (list.size() == 1) {
362             PersonEntity dbPerson = list.get(0);
363 
364             Random rnd = new Random();
365             while (buf.length() < 30) {
366                 buf.append(rnd.nextInt(16));
367             }
368             dbPerson.setResetPassword(buf.toString());
369             em.persist(dbPerson);
370         } else {
371             throw new DataCheckingException("Can not find email in Database");
372         }
373         return buf.toString();
374     }
375 
376     /**
377      * Human friendly name of person.
378      *
379      * @return
380      */
381     public String getName() {
382         if (getEntity() == null ){
383             return "";
384         } else {
385             return getEntity().toString();
386         }
387     }
388     
389     
390     public String getXmlId() {
391         if (getEntity() == null ){
392             return "";
393         } else {
394             String xmlId = getEntity().getXmlId();
395             if (!xmlId.equals("")) {
396                 return getEntity().getXmlId();
397             }
398             return getName().trim().toLowerCase().replaceAll(" ", "");
399         }
400     }
401     
402     
403     @SuppressWarnings("unchecked")
404     private boolean findEntity(EntityManager em, String email){
405         
406         Query query = em.createNamedQuery("findPersonByEmail");
407         query.setParameter("email", email);
408         List<PersonEntity> list = query.getResultList();
409 
410         if (list.size() >= 1) {
411             setEntity(list.get(0));
412             return true;
413         }
414         return false;
415     }
416 
417     /**
418      * This is to fix XML data problems.
419      *
420      * @param oldXmlCode
421      * @return
422      */
423     public static String convertOldXmlCountryCodesToISO(final String oldXmlCode) {
424 
425         String code = oldXmlCode.toUpperCase(Locale.ENGLISH);
426         if ("UK".equals(code) || "ENGLAND".equals(code)) {
427             return "GB";
428         } else if ("USA".equals(code)) {
429             return "US";
430         } else if ("JAPAN".equals(code)) {
431             return "JP";
432         } else if ("SOUTH AFRICA".equals(code)) {
433             return "ZA";
434         } else if ("FRANCE".equals(code)) {
435             return "FR";
436         } else if ("AUSTRALIA".equals(code)) {
437             return "AU";
438         } else if ("UNITED KINGDOM".equals(code)) {
439             return "GB";
440         } else if ("SINGAPORE".equals(code)) {
441             return "SG";
442         } else if ("GERMANY".equals(code)) {
443             return "DE";
444         } else if ("HOLLAND".equals(code)) {
445             return "NL";
446         } else if ("ITALIA".equals(code)) {
447             return "IT";
448         } else if ("SWEDEN".equals(code)) {
449             return "SE";
450         } else if ("FINLAND".equals(code)) {
451             return "FI";
452         } else if ("ITALY".equals(code)) {
453             return "IT";
454         } else if ("DENMARK".equals(code)) {
455             return "DK";
456         } else if ("AUSTRIA".equals(code)) {
457             return "AT";
458         }
459         
460         return oldXmlCode.toUpperCase();
461     }
462     
463     /**
464      * Change the email address in the enitity if it is unique.
465      *
466      * @param email
467      */
468     public void replaceEmail(EntityManager em, String email)
469             throws DataCheckingException {
470         
471         if (!email.equals(this.getEntity().getEmail())) {
472             if (findEntity(em, email)) {
473                 throw new DataCheckingException("Email address already in database.");
474             } else {
475                 this.getEntity().setEmail(email);
476             }
477         }
478     }
479 
480     // TODO: Implement isOnWorldsCommitte
481     public boolean isOnWorldsCommitte(){
482         return false;
483     }
484 
485     // TODO: Implement isCurrentMember
486     public boolean isCurrentMember(){
487         return false;
488     }
489     
490     // TODO: Implement getOnNationalCommittee
491     public boolean getOnCommittee(EntityManager em){
492         AssociationDAO assDAO = new AssociationDAO();
493         if (assDAO.findCommitteeMemberships(em, this.getEntity()).size() > 0) {
494             return true;
495         } else {
496             return false;
497         }
498     }
499 
500     public AssociationBO[] getCommitteeMemberships(EntityManager em) {
501         
502         AssociationDAO assDAO = new AssociationDAO();
503         List<CommitteeMemberEntity> list = assDAO.findCommitteeMemberships(em, this.getEntity());
504         AssociationBO[] associations = new AssociationBO[list.size()];
505         
506         for (int i=0; i < associations.length; i++){
507             associations[i] = new AssociationBO();
508             associations[i].setEntity(list.get(i).getAssosiation());
509         }
510         
511         return associations;
512     }
513     
514     public AssociationBO[] getOficialIMCACommitteeMemberships(EntityManager em) {
515         
516         AssociationBO[] associations = getCommitteeMemberships(em);
517         Vector<AssociationBO> vec = new Vector<AssociationBO> ();
518           
519         for (int i=0; i < associations.length; i++){
520             if (associations[i].getEntity().getIsOfficiallyImca()) {
521                 vec.add(associations[i]);
522             }
523         }
524         AssociationBO[] imcaAssociations = new AssociationBO[vec.size()];
525         for (int i=0; i < imcaAssociations.length; i++){
526             imcaAssociations[i] = vec.get(i);
527         }
528         return imcaAssociations;
529     }
530     
531 
532     public String getDefaultCountryCode() {
533         if (this.getEntity() != null) {
534             return this.getEntity().getAddress().getCountryCode();
535         }
536         return "";
537     }
538 
539     public void sendMembershipRequestMail(EntityManager em,
540             MembershipTypeEntity memType) throws MessagingException {
541 
542         MimeMessage message = ImcaUtils.createEmailMessage();
543         InternetAddress toEmail = new InternetAddress(getEntity().getEmail());
544         
545         message.setRecipients(MimeMessage.RecipientType.TO,
546                 new InternetAddress[] { toEmail });
547         
548         AssociationBO association = new  AssociationBO(memType.getAssociation());
549         InternetAddress[] ccEmail = association.getCommitteeEmails();
550         message.setRecipients(MimeMessage.RecipientType.CC, ccEmail);
551         
552         message.setSubject(ImcaUtils.getMessage("mailMembershipRequestSubject", 
553                 this.getLocale()) + " " + memType.toString(),
554                 ImcaUtils.MAIL_ENCODING);
555         
556         message.setText(this.getName() + "\n\n" +
557                 ImcaUtils.getMessage("mailMembershipRequestBody", this.getLocale()) +
558                 "\n\n" + 
559                 buildMembershipTypeEntityTextSummery(memType, true), 
560                 ImcaUtils.MAIL_ENCODING);
561         Transport.send(message);
562     }
563 
564     public void sendMembershipConfirmationMail(EntityManager em,
565             MembershipTypeEntity memType) throws MessagingException {
566         
567         MimeMessage message = ImcaUtils.createEmailMessage();
568         InternetAddress toEmail = new InternetAddress(getEntity().getEmail());
569         
570         message.setRecipients(MimeMessage.RecipientType.TO,
571                 new InternetAddress[] { toEmail });
572         
573         AssociationBO association = new  AssociationBO(memType.getAssociation());
574         InternetAddress[] ccEmail = association.getCommitteeEmails();
575         message.setRecipients(MimeMessage.RecipientType.CC, ccEmail);
576         
577         message.setSubject(ImcaUtils.getMessage("mailMembershipRequestConfirmationSubject", 
578                 this.getLocale()) + " " + memType.toString(),
579                 ImcaUtils.MAIL_ENCODING);
580         
581         message.setText(this.getName() + "\n\n" +
582                 ImcaUtils.getMessage("mailMembershipRequestConfirmBody", this.getLocale()) +
583                 "\n\n" + 
584                 buildMembershipTypeEntityTextSummery(memType, false), 
585                 ImcaUtils.MAIL_ENCODING);
586         Transport.send(message);
587     }
588     
589     private String buildMembershipTypeEntityTextSummery(MembershipTypeEntity memType,
590             boolean withPaymentDetails){
591         if (withPaymentDetails) {
592             return memType.getAssociation().toString() + "\n" +
593                 memType.getValidFrom() + " - " + memType.getValidTo() + "\n" +
594                 memType.getCurrentFee().getCurrency() + " " + memType.getCurrentFee().getAmount() + "\n" +
595                 memType.getAssociation().getPaymentExplanation();
596         } else {
597             return memType.getAssociation().toString() + "\n" +
598                 memType.getValidFrom() + " - " + memType.getValidTo() + "\n" +
599                 memType.getCurrentFee().getCurrency() + " " + memType.getCurrentFee().getAmount();
600         }
601     }
602 
603     public String getCountry() {
604         if (getEntity() == null) {
605             return "";
606         }
607         Locale loc = new Locale("en", getEntity().getAddress().getCountryCode());
608         
609         return loc.getDisplayCountry(new Locale("en"));
610     }
611     
612     
613     public String getAddressHtml() {
614         
615         StringBuffer buf = new StringBuffer();
616         if (getEntity().getAddress().getStreet1().length() > 0) {
617             buf.append(getEntity().getAddress().getStreet1() + "<br />");
618         }
619         if (getEntity().getAddress().getStreet2().length() > 0) {
620             buf.append(getEntity().getAddress().getStreet2() + "<br />");
621         }
622         if (getEntity().getAddress().getCity().length() > 0) {
623             buf.append(getEntity().getAddress().getCity() + "<br />");
624         }
625         if (getEntity().getAddress().getPostCode().length() > 0) {
626             buf.append(getEntity().getAddress().getPostCode() + "<br />");
627         }
628         buf.append( getCountry() + "<br />");
629         
630         return buf.toString();
631     }
632 
633     public String getSmallPictureUrl() {
634         
635         return "/img/riders/" + getXmlId() + ".jpg";
636     }
637     
638     public String getRiderPageUrl(){
639         return "/imca/faces/rider.jsp?id=" + entity.getId();
640     }
641 
642 }