Wednesday, 9 June 2010

JavaMail, Commons Mail or Spring Mail - Which does the job?

I thought since the previous culprit focuses on e-mail, it would be essential if I hit the nail on the head with choosing the right API for your e-mail function. For a starter, building e-mail function can be a little fustrating task.

If you are like most developers, you delve in JavaMail API thinking that is it, you have found a boiler plate code which does the job. You then go ahead to customize it to suite your enviroment, finally deployed it to realise your pain has just began.

Take for for instance below JavaMail API generic code:

Email Interface
  public interface EmailEngine
  {
    public void MailTransport(String from, String to, String cc, String subject,
     String message, String doc, String bcc) throws Exception;
  }

Actual Implementation
 public class EmailEngineImpl implements EmailEngine

    public final void MailTransport(String from, String to, String cc, String subject,
     String message, String doc, String bcc)
    {
      Properties props = new Properties();
      props.put(PropsFactory.PropsLookup("mail.host.props"), 
               PropsFactory.PropsLookup("mail.host"));
      Session session = Session.getInstance(props);
      try
      {
        Message msg = new MimeMessage(session);
        MimeMultipart mpRoot = new MimeMultipart();
        MimeMultipart mpAl = new MimeMultipart("alternative");
        MimeBodyPart content = new MimeBodyPart();

        msg.setSubject(subject);
        msg.setSentDate(Today.getDate());
        msg.setFrom(new InternetAddress(from));
        msg.setRecipients(Message.RecipientType.TO, getAddress(to));

        if (cc != null)
        {
          msg.setRecipients(Message.RecipientType.CC, getAddress(cc));
        }
        if (!(bcc == null))
        {
          msg.setRecipients(Message.RecipientType.BCC, getAddress(bcc));
        }
        
        if (doc != null)
        {
          MimeBodyPart p1 = new MimeBodyPart();
          Resource file = new ClassPathResource(doc);
          FileDataSource fds = new FileDataSource(file.getFile())
          {
            public String getContentType()
            {
              return "application/octet-stream";
            }
          };

          p1.setDataHandler(new DataHandler(fds));
          p1.setFileName(fds.getName());
          mpRoot.addBodyPart(p1);
        }
        MimeBodyPart p2 = new MimeBodyPart();
        p2.setText(message);
        mpAl.addBodyPart(p2);

        content.setContent(mpAl);
        mpRoot.addBodyPart(content);

        msg.setContent(mpRoot);
        msg.saveChanges();

        Transport.send(msg);
      }
      catch (Exception ex)
      {
        ex.printStackTrace();
      }
    }
  }
Everything looks fine except you deploy it to realise, Some Email clients typically outlook will work fine but little issues with others. And so you dig around to uncover you'll have to follow the MimeMultiPart structure, WHAP!

You have little time to waste therefore decided to try native Spring Email API. Bravo! Take time to read the API document, did you see the line which says:


Warning regarding multipart mails: Simple MIME messages that just contain HTML text but no inline elements or attachments will work on more or less any email client that is capable of HTML rendering. However, inline elements and attachments are still a major compatibility issue between email clients: It's virtually impossible to get inline elements and attachments working across Microsoft Outlook, Lotus Notes and Mac Mail. Consider choosing a specific multipart mode for your needs: The javadoc on the MULTIPART_MODE constants contains more detailed information.

You avoid the warning and implement Spring Generic Email API as shown below, perhaps tweaking static MULTIPART_MODE to see if it does support various multi email clients. WGL!
NB. Inject org.springframework.mail.javamail.JavaMailSender

  public final void MailTransport(String from, String to, String cc, 
   String subject, String content, String doc, String bcc)
  {
    try
    {
      MimeMessage message = mailSender.createMimeMessage();
      // use the true flag to indicate you need a multipart message
      MimeMessageHelper helper = new MimeMessageHelper(message, true);
      helper.setFrom(from);
      helper.setTo(getAddress(to));
      helper.setSubject(subject.toString());

      if (!(cc == null))
      {
        helper.setCc(getAddress(cc));
      }
      if (!(bcc == null))
      {
        helper.setBcc(getAddress(bcc));
      }

      if (!(doc == null))
      {
        Resource file = new ClassPathResource(doc);
        helper.addAttachment(file.getFilename(), file);
      }

      helper.setText(content);
      mailSender.send(message);
    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
  }

If you do have luck with either Generic JavaMail or Spring implementation, I suppose your first reaction will be, why bother trying Apache Commons Email! You want MHO, go ahead and try it. It saves time and does the job. Well each of these API has it flaws, but TMHO Apache Commons Email ticks most boxes. Get the dependency or the jar file onto your classpath and try this;


  public class EmailEngineImpl implements EmailEngine
  {
    public final void MailTransport(String from, String to, String cc, String subject, String message, String doc, String bcc)
    {
      // Create Multi-Part document
      MultiPartEmail email = new MultiPartEmail();
      try
      {
        if (!(doc == null))
        {
          // Create the attachment
          EmailAttachment attachment = new EmailAttachment();
          Resource file = new ClassPathResource(doc);
          
          attachment.setURL(file.getURL());
          attachment.setDisposition(EmailAttachment.ATTACHMENT);
          attachment.setName(file.getFilename());

          // add the attachment
          email.attach(attachment);
        }

        // Set Mail server location
        email.setHostName(PropsFactory.PropsLookup("mail.host"));
        email.setTo(getAddress(to));
        email.setFrom(from);

        if (!(cc == null))
        {
          email.setCc(getAddress(cc));
        }

        if (!(bcc == null))
        {
          email.setBcc(getAddress(bcc));
        }
        email.setSubject(subject);
        email.setMsg(message);

        // Send message
        email.send();
      }
      catch (Exception ex)
      {
        ex.printStackTrace();
      }
    }
  }
I did try these and realised, most little issues like multi client and attachment was dealt with. Like I said this is my opinion let me know what you think. And oh if you wondering WTF is the method getAddress(..), see below:

Implementation for Apache Commons
  private Collection getAddress(String arg)
  {
    Collection address = new ArrayList();
    try
    {
      ArrayList ccArray = new ArrayList();
      StringTokenizer st = new StringTokenizer(arg, ",");
      while (st.hasMoreTokens())
      {
        ccArray.add(new InternetAddress(st.nextToken()));
      }

      for (int i = 0; i < ccArray.size(); i++)
      {
        address.add(ccArray.get(i));
      }

    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
    return address;
  }
Implementation for JavaMail or Spring
 private InternetAddress[] getAddress(String arg)
  {
    InternetAddress[] address = null;
    try
    {
      ArrayList ccArray = new ArrayList();
      StringTokenizer st = new StringTokenizer(arg, ",");

      while (st.hasMoreTokens())
      {
        ccArray.add(new InternetAddress(st.nextToken()));
      }

      int size = ccArray.size();
      address = new InternetAddress[size];
      for (int i = 0; i < size; i++)
      {
        address[i] = new InternetAddress(ccArray.get(i).toString());
      }

    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
    return address;
  }

Drop me a comment to let me know what you think.

Monday, 7 June 2010

Commons mail, JavaMail or Spring Mail with Maven2 and servlet container dependency issue.

If you are working on Spring Web project with Axis2, Axiom or Apache CXF 2 dependency, unless the application do not have concerns with e-mail confirmation/notification functionality. Else you are likely to run into this culprit.
How do you know you've got this issue? You execute a test application from your IDE to see if an e-mail will be sent, to your surprise everything works perfect. But when you deploy the application to either Tomcat, Jboss or Glassfish server, the message is sent with header and footer details as part of the mesage body. The massage body typically resembles below;
------=_Part_0_25002283.1275298567928
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hello Mark Doe,

This message is found as a culprit.

Regards,

Joe Blahh

------=_Part_0_25002283.1275298567928

Also if you are attaching documents to this email message, the attachment is sent with base64 encode as part of the message body. Typical attachment message will look like this;

------=_Part_0_25002283.1275298567928
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hello Mark Doe,

This message is found as a culprit.

Regards,

Joe Blahh

------=_Part_0_25002283.1275298567928
Content-Type: application/pdf; name="file.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; 
filename="file.pdf"
Content-Description: Some attachment

JVBERi0xLjQNJeLjz9MNCjYzIDAgb2JqDTw8L0xpbmVhcml6ZWQgMS9MIDMxMzE4Mi9PIDY1L0Ug
Mjg2NjY5L04gMS9UIDMxMTgwMi9IIFsgMjgzNiAzNzZdPj4NZW5kb2JqDSAgICAgICAgICAgICAg
DQp4cmVmDQo2MyAxMjcNCjAwMDAwMDAwMTYgMDAwMDAgbg0KMDAwMDAwMzM4MCAwMDAwMCBuDQow
MDAwMDAzNTIzIDAwMDAwIG4NCjAwMDAwMDQzMDcgMDAwMDAgbg0KMDAwMDAwNTEwOSAwMDAwMCBu
DQowMDAwMDA2Mjc5IDAwMDAwIG4NCjAwMDAwMDY0MTAgMDAwMDAgbg0KMDAwMDAwNjU0NiAwMDAw
MCBuDQowMDAwMDA3OTY3IDAwMDAwIG4NCjAwMDAwMDkwMjMgMDAwMDAgbg0KMDAwMDAwOTk0OSAw
MDAwMCBuDQowMDAwMDExMDAwIDAwMDAwIG4NCjAwMDAwMTIwNTkgMDAwMDAgbg0KMDAwMDAxMjky
MCAwMDAwMCBuDQowMDAwMDEyOTU0IDAwMDAwIG4NCjAwMDAwMTI5ODIgMDAwMDAgbg0KMDAwMDAx
.......
CnN0YXJ0eHJlZg0KMTE2DQolJUVPRg0K
------=_Part_0_25002283.1275298567928--

If you've run into this culprit, don't worry too much. Go grab a cuppa coffee, and while you're relaxed look through your Maven dependency to see if you have geronimo-javamail_1.4_spec-1.2 along with geronimo-activation_1.1_spec, because your project build will rely on these. You can do this by issuing below Maven2 commands;
mvn dependency:tree
Optionally, the output parameter can be specified to divert the output to a file:
mvn dependency:tree -Doutput=/path/to/file

Causes:
The described issue is caused by transitive dependencies of Apache CXF 2 or Axiom.

SOLUTION:
To resolve this issue, exclude geronimo-javamail_1.4_spec from the build, and just rely on javax's mail-1.4.x.jar.

    
  org.apache.cxf   
  cxf-rt-frontend-jaxws    
  2.2.6    
            
                  
       org.apache.geronimo.specs            
       geronimo-javamail_1.4_spec        
      
      
      org.apache.geronimo.specs 
      geronimo-activation_1.1_spec
         
 



  
  org.apache.ws.commons.axiom  
  axiom-api  
  1.2.8  
           
      
      org.apache.geronimo.specs 
      geronimo-activation_1.1_spec
     
     
      org.apache.geronimo.specs 
      geronimo-javamail_1.4_spec
     
    

Thursday, 15 April 2010

Accessing properties file using Java and Spring.

You can save crosscutting data in a properties file for your Java application. This approach has been adopted by several application and consequently not unconventional to see various post related to this subject. And so today, after scratching my chin for thoughts on what to post, I decided to highlight slightly on this rather conventional approach.

Typical crosscutting details includes username, password, connection urls, MIME types etc. For Java applications, saving these data in a properties file avoid having to dig through your codes to re-factor changes, re-compile and hence deploy.

So if you are a beginner looking for 'How to' or an advance looking for a quick refresh, this is how it is done. First create a properties file and save it in your classpath. Typical properties file looks as shown below:
#File name is 'yourfile.properties'
#This file holds crosscutting details.

database.username=your username
database.password=your password
database.url=jdbc:mysql//your url

lang=eng
lang=ger
Core Java option
Then to access values within this properties file, you build a simple handler util as shown below with various helper functions to aid access the elements within the properties file.
public class PropsUtil
{
  private static Logger logger = Logger.getLogger(PropsUtil.class);
  private final static String file = "yourfile.properties";//Properties file name
  private static Properties props = null;

  /**
   * Find the properties file in the class path and load it.
   * @throws IOException
   */
  private static void loadPropertiesFromClasspath() throws IOException
  {
    props = new Properties();
    InputStream inputStream = PropsUtil.class.getClassLoader().getResourceAsStream(file);

    if (inputStream == null)
    {
      throw new FileNotFoundException("Property file '" + file + "' not found in the classpath");
    }
    props.load(inputStream);
  }

  /**
   * Look up a property from the properties file.
   * @param key The name of the property to be found
   * @return The value of the property
   */
  public static String getProperty(String key)
  {
    if (props == null)
    {
      try
      {
        loadPropertiesFromClasspath();
      }
      catch (Exception IOException)
      {
        logger.warn("Unable to load properties file.");
        return null;
      }
    }
    return props.getProperty(key);
  }

  /**
   * Look up a property from the properties file.
   * @param key The name of the property to be found
   * @return The value of the property
   */
  public static String getProperty(String key, String defaultValue)
  {
    if (props == null)
    {
      try
      {
        loadPropertiesFromClasspath();
      }
      catch (Exception IOException)
      {
        logger.warn("Unable to load properties file.");
        return null;
      }
    }
    return props.getProperty(key, defaultValue);
  }

  /**
   * Looks up the value of a key from the properties file and converts it to an integer.
   * @param key
   * @return The value of that key
   */
  public static int getIntProperty(String key)
  {
    String property = getProperty(key);

    if (property == null)
    {
      logger.warn("Could not load integer property " + key);
      return -1;
    }
    try
    {
      return Integer.parseInt(property);
    }
    catch (NumberFormatException nfe)
    {
      logger.warn("Invalid format for a number in properties file: " + property, nfe);
      return -1;
    }
  }
}
Using above util we can access the value of database.username in our file simply like this:
 String dbUser=PropsUtil.getProperty("database.username");//access using property name
 String dbUser=PropsUtil.getProperty("lang", "ger");//fetch match value using both property name and default value
Spring based
Another option is Spring base properties injection. It is common this days to adapt a common framework to wrap your application, one typical framework which has grown with strength over the years is Spring. Like other frameworks Spring comes packed with wrappers for almost anything your application is deemed to support, and one that this post is concern is wrapper for properties file.

PropertyPlaceholderConfigurer wrapper is the most common and easy properties file injector bean supported and used mostly by Spring based application. A typical usage is as straight forward as shown below:

   
 

 
  ${database.username}
 

Note the setting classpath:yourfile.properties assumes yourfile.propertie is located at your project classpath location src/main/resources.

Annotations option
Spring also provides you another wrapper for injecting properties into your bean using annotations. This makes it handy for accessing values at application level. For example classes which are not defined in your-app-context.xml as beans can still access this properties using annotations. Achieving this is as simple as adding below definition:
 
This provides access to the properties via simple constucts as demostrated in below class:
 public class Example
 {
  @Value("#{myAppProps['database.username']}")
  private String dbUser;
 
  public void foo()
  {
   System.out.println(dbUser);
  }
 }
So far you have seen how to construct a simple util class using Core Java to handlle properties file. You have also seen how easy to use Spring based support wrappers to handle properties within your application. Please do let me know if you have any suggestion or enchancement or if this post has helped you in some way.

Tuesday, 30 March 2010

Exception in thread "main" org.hibernate.ObjectNotFoundException: No row with the given identifier exists:

Are you working on Hibernate Many-To-One/One-To-Many with MySQL? If you're, then beware of this culprit. So how does it happens? You have two objects say 'Site' and 'Partner'. Here 'A' Partner will be dealing with multiple sites and hence the multiplicity of Many-To-One and One-To-Many mapping from both objects.

For example the Site mapping will resemble something like this;
  @Entity
  @Table(name = "site")
  public class Site
  {
    private Partner partner;
    public Site()
    {
      super();
    }

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "partnerid", nullable = true)
    public Partner getPartner()
    {
      return partner;
    }

    public void setPartner(Partner partner)
    {
      this.partner = partner;
    }
  }

While the Partner object mapping will resemble something like this;
  @Entity
  @Table(name = "partner")
  public class Partner
  {
    private List<Site> sites;
    public Partner()
    {
      super();
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "partner")
    public List<Site> getSites()
    {
      return sites;
    }

    public void setSites(List<Site> sites)
    {
      this.sites = sites;
    }
  }


From the above mappings, you'll notice that Partner has been mapped to Site using the partnerid of MySQL Table partner. A physical schema for partner and site Tables looks like this;
 Partner:
 +-----------+-------------+------+-----+
 | Field     | Type        | Null | Key |
 +-----------+-------------+------+-----+
 | id        | int(11)     | NO   | PRI |
 | name      | varchar(50) | NO   |     |
 +-----------+-------------+------+-----+

 Site:
 +-----------+-------------+------+-----+
 | Field     | Type       | Null  | Key |
 +-----------+-------------+------+-----+
 | id        | int(11)    | NO    | PRI |
 | sitename  | varchar(50)| NO    |     |
 | partnerid | int(11)    | NO    |     |
 +-----------+-------------+------+-----+
 

Because the PartnerID is integer if you have a method say getParent() in Site for example like this;
  @Transient
  public Company getParent()
  {
    if (!(getPartner() == null))
    {
      return getPartner();
    }
    return null;
  }

In MySQL , default integer is '0' , not NULL. This will cause Hibernate String to load a Partner with non-existent row with id=0 and therefore throw:
 Exception in thread "main" org.hibernate.ObjectNotFoundException: No
 row with the given identifier exists: [com.lop.testing.Partner#0]at
 org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:409)at
 org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:108)at
 org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:97)at
 org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)at
 org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)at
 com.essensys.bluefin.Partner_$$_javassist_10.toString(Partner_$$_javassist_10.java)at 
 java.lang.String.valueOf(String.java:2826) at java.lang.StringBuilder.append(StringBuilder.java:115)

To resolve this, simply annotate the Site getPartner() method as shown below;
  @ManyToOne(fetch = FetchType.LAZY, optional = false)
  @JoinColumn(name = "partnerid", nullable = true)
  @NotFound(action = NotFoundAction.IGNORE)
  public Partner getPartner()
  {
    return partner;
  }

The existance
@NotFound(action = NotFoundAction.IGNORE)
fix the issue.
Job done! but then the question is, do you need to go through that?

Tuesday, 23 March 2010

java.lang.NoSuchMethodError: javax.xml.ws.WebFault.messageName()Ljava/lang/String

What a weird title to start with. I have to say the caption needs to be pretty straight forward to address the related issue. So what is it? Apache CXF developers working on JAX-WS OR JAX-RS project on Maven and Java 6 are likely to experience this exception.


Exception in thread "main" java.lang.NoSuchMethodError: javax.xml.ws.WebFault.messageName()Ljava/lang/String;
[java] at com.sun.xml.ws.model.RuntimeModeler.processExceptions(RuntimeModeler.java:1162)
[java] at com.sun.xml.ws.model.RuntimeModeler.processDocWrappedMethod(RuntimeModeler.java:898)
[java] at com.sun.xml.ws.model.RuntimeModeler.processMethod(RuntimeModeler.java:666)
[java] at com.sun.xml.ws.model.RuntimeModeler.processClass(RuntimeModeler.java:420)
[java] at com.sun.xml.ws.model.RuntimeModeler.buildRuntimeModel

After digging around you'll realised the only option is to download the webservices-api.jar file, plus wack it onto C:\Program Files\Java\jdk1.6.0_18\jre\lib\endorsed directory to resolve it.

You might have probably ask yourself by now, where to grab webservices-api.jar easily from? two advice, download metro, unzip its content and the finally reach the lib directory to locate it OR right here.

Hold on! does it really resolves it? You are likely to enter into another annoyance when finally below exception spits onto your console log:

Exception in thread "main" java.lang.ClassCastException: $Proxy66 cannot be cast to com.sun.xml.internal.ws.developer.WSBindingProvider.

Like most people, the first thing that comes to mind is revisit and amend your service login object to see if it does the job. You are likely also to be told 'since you’re using CXF and not the JAX-WS reference implementation, the steps to set headers are probably going to be different and therefore Check the CXF docs', forgetting Apache CXF supports both JAX-WS OR JAX-RS implementations.

I tell you what don't explode yourself from annoyance, just take a close look at the Exception. You're referencing some of your object imports from com.sun.xml.internal.ws, and there is where your issue is.

Do NOT bombard yourself with new exceptions trying to regenerate your stubs with extra arguments as shown below, suggested by few people on the web.


-exsh
true


To resolve this Exception, just replace;

import com.sun.xml.internal.bind.api.JAXBRIContext;
import com.sun.xml.internal.ws.api.message.Header;
import com.sun.xml.internal.ws.api.message.Headers;
import com.sun.xml.internal.ws.developer.WSBindingProvider;

With

import com.sun.xml.bind.api.JAXBRIContext;
import com.sun.xml.ws.api.message.Header;
import com.sun.xml.ws.api.message.Headers;
import com.sun.xml.ws.developer.WSBindingProvider;


Job done! Now go grab a cuppa coffee and relax.

Saturday, 6 February 2010

Demise of waterfall, concept or reality?


Agile development approach has been the most adopted methodology for 21st century development, and software project management. "Some have said that 2007 was the year that Agile arrived, with agile development best practices such as automated builds, test automation, and continuous integration finally beginning to reach critical mass among Java developers. While this is true in theory, the fact is that most Java enterprise projects are still based on more traditional development methods, such as the Waterfall model".

Take Scrum for instance, we know a strongly modelled scrum is a projects that are "divided into succinct work cadences, known as sprints, which are typically one week, two weeks, or three weeks in duration. At the end of each sprint, stakeholders and team members meet to assess the progress of a project and plan its next steps".

Isn’t this what developers and stakeholders has conceptually been practicing since the prime times of waterfall, which many believe is at its demise. At each stage of the waterfall model is a well iterative concept (such as Scrum) adopted to make sure before we proceed to the next stage of the development process, deliverables would have been well designed, coded and well tested.

Waterfall methodology is still utilised in today’s software development, practically because – each stage of the development process is an adopted agile process interactively and iteratively utilised to derive a quality working product. One might argue, but waterfall never iterates the actual project, simply because water flows downwards and ends there.

When a project exit the deadline, it has exited the deadline - any subsequent call for modification triggers a call for design changes, code modification, testing and walkthrough and modification of documentations and re-implementation. This put together is water pouring from one glass to another.

Friday, 5 February 2010

Trusting the untrusted.


Most internet users are reluctant to change their password, trusting they are not victims of exploits. Well I suppose we all do it thinking what possibly could our credential worth. Password change is very vital when operating from home networks. These are more susceptible to exploit attack as witness from Twitter and not long ago Hotmail. "An intruder doesn't have to be inside your home or office building to manipulate a wireless signal. For example, they could be sitting outside in their car sniffing out your data all while enjoying a sandwich. Before they have a chance to complete the meal, the intruder can learn just who you work for, how to access the company network or even transfer money out of your bank account if the right security is not implemented."

Not only that, changing your web password from work area networks can be prone to exploits due to exploit sniffing tools utilised by trusted network and security engineers and other internal staffs, to filter, sniff and intrude in our private mails and explore your private life around social networks. I think everyone is purely aware of the capabilities of the expert, consequently an oversight and perhaps a little trust is what is keeping our virtual instance alive.

A few days ago "Officials at Twitter linked the resetting of passwords to a malicious Torrent sites and other schemes. According to Twitter, the company began its investigation after noticing a surge in followers for certain accounts during the past five days. Twitter revealed more details about the phishing attacks that caused the company to reset the passwords on some user accounts today." Darknet blogged.

"According to Twitter Director of Trust and Safety Del Harvey, there was a sudden surge in followers for certain accounts during the last five days. For that reason, the company decided to push out a password reset to the accounts, he said. After launching an investigation, Twitter officials linked part of the problem to malicious torrent sites." Darknet blogged.

"It appears that for a number of years, a person has been creating torrent sites that require a login and password as well as creating forums set up for torrent site usage and then selling these purportedly well-crafted sites and forums to other people innocently looking to start a download site of their very own," Harvey blogged. "However, these sites came with a little extra — security exploits and backdoors throughout the system. This person then waited for the forums and sites to get popular and then used those exploits to get access to the username, email address, and password of every person who had signed up."