KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > oyster > smime > SignedAndEnvelopedSMIME


1 /*
2  * Title: Oyster Project
3  * Description: S/MIME email sending capabilities
4  * @Author Vladan Obradovic
5  * @Version 2.1.5
6  */

7
8 package org.enhydra.oyster.smime;
9
10 import org.enhydra.oyster.activation.CMSEnvelopedDataSource;
11 import org.enhydra.oyster.activation.CMSSignedDataSource;
12 import org.enhydra.oyster.exception.SMIMEException;
13 import org.enhydra.oyster.crypto.consts.EnvelopedConstants;
14 import org.enhydra.oyster.util.MimeAssist;
15 import javax.mail.Multipart JavaDoc;
16 import javax.mail.internet.MimeMessage JavaDoc;
17 import javax.mail.internet.MimeBodyPart JavaDoc;
18 import javax.mail.internet.MimeMultipart JavaDoc;
19 import javax.activation.DataHandler JavaDoc;
20 import java.util.Vector JavaDoc;
21 import java.util.TimeZone JavaDoc;
22 import java.util.GregorianCalendar JavaDoc;
23 import java.io.FileInputStream JavaDoc;
24 import java.io.InputStream JavaDoc;
25 import java.security.PrivateKey JavaDoc;
26 import java.security.KeyStore JavaDoc;
27 import java.security.cert.X509Certificate JavaDoc;
28
29 /**
30  * SignedAndEnvelopedSMIME class is used for creating and sending signed and
31  * encrypted, or encrypted and signed S/MIME messages. Which process will be
32  * first (encrypting or signing) is defined in the method signingAndEnveloping
33  * by using appropriate parameter: SIGN_FIRST or ENCRYPT_FIRST.<BR>
34  * <BR>
35  * Email message is in general composed of the content of the message and of one or
36  * more attachments. The content is visible part of the message, and attacments are
37  * mostly files or other binary data, which are not visible parts of message and
38  * which are used by email as a transport medium. In this implementation content
39  * can be represented in two different forms: <BR>
40  * <BR>
41  * <UL><LI>
42  * text/plain (only text withouth any formating) or
43  * </LI> <LI>
44  * text/html (html coded view of message)
45  * </LI></UL>
46  * Also, content can be absent, but than at least one attachment must be added.
47  * Content can be set on few manners. For text/plain type it can be done in time
48  * of construction with constructor designed special for creation of text/plain
49  * messages. Also, text content can be created by any of setContent() methods,
50  * if construction of object was done by other constructor which creates object
51  * with empty content. Construction with other constructor offers a few different
52  * posibilities for importing content data (File, InputStream, String) by using
53  * appropriate setContent() method. If method with four parameters is used, 3rd
54  * ant 4th parameters are not in use for text/plain message and could be set to
55  * null. For setting text/html content, construction of object should be done
56  * only by second mentioned constructor, which creates object with empty content.
57  * Content should be populated by html code with setContent() method. 3rd
58  * parameter is used for resolving relative addresses of resources in html
59  * code (images, movies...) and 4th parameter serves as data source for resources
60  * that are on special way addressed in html code. Also, there is a setContent()
61  * method which doesn't care about resources and which creates message content
62  * withouth them. For more information refer to setContent() methods.<BR>
63  * <BR>
64  * Message can contain any number of attachments. Also, message can
65  * be wihouth any attachment, but then content must be present. Every attachment
66  * should be added by performing single addAttachment() method. Attachments
67  * can be added from file or from InputStream. Mime-type which corresponds to
68  * particular attachment is obtained according to extension of file name
69  * (virtual or real file name) passed to addAttachment() method. File mime.types
70  * in META_INF directory contains list of mime-types and corresponding extensions
71  * which are used in determination of mime-type. File can be changed to satisfy
72  * secific requrements. For more information refer to addAttachmenttent()
73  * method.<BR>
74  * <BR>
75  * Encryption of message is performed by symmetric encryption with random
76  * generated symmetric key. This key is then encrypted by assymetric encryption
77  * with a recipient's public key, and sent together with encrypted message to
78  * recipient in CMS (Cryptographic Message Syntax) enveloped object. For all
79  * recipients of message (if there is more than one) operation of encrypting
80  * symmetric key must be performed with his corresponding public key (from .cer
81  * file). Encryption can be performed by following algorithms and corresponding
82  * key sizes:<BR>
83  * RC2_CBC, 40 bits (default encryption)<BR>
84  * RC2_CBC, 64 bits<BR>
85  * RC2_CBC, 128 bits<BR>
86  * DES, 56 bits<BR>
87  * DES_EDE3_CBC, 128 bits<BR>
88  * DES_EDE3_CBC, 192 bits<BR>
89  * <BR>
90  * As a asymmetric algorithm, RSA algorithm is used.<BR>
91  * <BR>
92  * Message is implicitly signed in the case of both processing (signing
93  * and enveloping). External signing allows email receiving clients withouth
94  * implemented SMIME capabilities to preview the signed SMIME email messages.
95  * This possibilities have no importance in the case of both signing and enveloping
96  * (or enveloping and signing) because, before or after signing, the message is
97  * encrypted, so it is not readable.<BR>
98  * <BR>
99  * Message can be signed with or without Signed Attributes. Signed Attributes
100  * are one optional part of CMS (Cryptographic Message Syntax) signed objects,
101  * and consist of some atributes used in the process of signing (date and time
102  * of signing, capabilities of sending email client, message digest value...).
103  * If those attributes are ommited, only pure message is taken in the process
104  * of signing.<BR>
105  * <BR>
106  * Digest algorithm can be SHA1, MD2 or MD5 which depends on selected signing algorithm.<BR>
107  * <BR>
108  * Capabilities Attributes are one of Signed Attributes, and in the process of
109  * signing (if Signed Attributes are involved) can be set. This attributes
110  * indicate to recipient email client which encipher, symmetric and/or signature
111  * algorithms signer's email client preferes, end they can be used in the next
112  * communication between each others. Setting this posibilities is optional, but
113  * if it is set, order of adding gives the information about most preferes algorithms
114  * within paricular group of algorithms. Defined Capabilities Attributes in this version
115  * of Signed SMIME can be from group: RC2 40, RC2 64, RC2 128, DES and DES_EDE3 for
116  * symmetric encryption algorihms, from group: MD2 with RSA, MD5 with RSA, SHA1 with RSA
117  * and SHA1 with DSA for signing algorithms, and RSA for encipher algorithm. For more
118  * information see setCapabilities method in this class.<BR>
119  * <BR>
120  * Certificates of signers and their root authorities can be included in the
121  * signed message. This posibilities allow the recipient of signed SMIME
122  * message to automatically include signer's certificates as trusted, and verify
123  * signed message. This posibilities are optional.<BR>
124  * <BR>
125  * More than one signer can perform signing of message and they can use
126  * different signing algorithms. Digital signing can be performed by SHA1_WITH_RSA,
127  * MD2_WITH_RSA, MD5_WITH_RSA or SHA1_WITH_DSA.<BR>
128  * <BR>
129  */

130 public class SignedAndEnvelopedSMIME extends BaseSignedSMIMEObject implements EnvelopedConstants
131 {
132   /**
133    * Simple constructor. Dynamically loads the BC and SUN provider necessary for
134    * cryptography processing. This constructor does not create MIME message
135    * object, so it is obligatory to invoke initMimeMessage() method after this
136    * constructor.
137    */

138   protected SignedAndEnvelopedSMIME ()
139   {
140     super();
141   }
142
143   /**
144    * Initializes the JavaMail session for SMTP and the MimeMessage object for message
145    * which will be sent. Dynamically loads the BC and SUN provider necessary for
146    * cryptography processing. This constructor is used for creating message with
147    * text/plain content. For creating html formated content (text/html), other
148    * constructor should be used in combination with one of setContent methods.
149    * Note that after using this constructor setContent method can be used only
150    * if "content" argument of constructor was given as null, otherwise setContent
151    * method can't be used because content is already set as text/plain.
152    * @param smtpHost name of SMTP host used for sending email
153    * @param fromAddress email address of sender (FROM field in email header)
154    * @param subject subject of email (SUBJECT field in email header). This
155    * argument can be null, but email message will be sent withouth SUBJECT.
156    * @param content text/plain content of email message. This argument can be
157    * null, but later one of setContent() methods or one of addAttachment()
158    * methods should be called
159    * @param charset character set for passed subject and content. The given
160    * Unicode string will be charset-encoded using the specified charset. The
161    * charset is also used to set the "charset" parameter. For example German
162    * letters should be encoded by usage of 'ISO-8859-1' charset. If charset
163    * parameter is null and subject or content contains non US-ASCII characters,
164    * it will be encoded using the platform's default charset.
165    * @exception SMIMEException if smtpHost or fromAddress parameters are null.
166    * Also, it can be caused by non SMIMEException which is MessagingException.
167    */

168   public SignedAndEnvelopedSMIME (String JavaDoc smtpHost, String JavaDoc fromAddress, String JavaDoc subject,
169                           String JavaDoc content, String JavaDoc charset) throws SMIMEException
170   {
171     super(smtpHost, fromAddress, subject, content, charset);
172   }
173
174
175   /**
176    * Initializes the JavaMail session for SMTP and the MimeMessage object for message
177    * which will be sent. Dynamically loads the BC and SUN provider necessary for
178    * cryptography processing. This constructor does not create content of message
179    * and it can be set later with one of setContent methods. Also, message can be
180    * left withouth content, but then at least one attachement must be added.
181    * @param smtpHost name of SMTP host used for sending email
182    * @param fromAddress email address of sender (FROM field in email header)
183    * @param subject subject of email (SUBJECT field in email header). This
184    * argument can be null, but email message will be sent withouth SUBJECT.
185    * @param charset character set for passed subject and content. The given
186    * Unicode string will be charset-encoded using the specified charset. The
187    * charset is also used to set the "charset" parameter. For example German
188    * letters should be encoded by usage of 'ISO-8859-1' charset. If charset
189    * parameter is null and subject or content contains non US-ASCII characters,
190    * it will be encoded using the platform's default charset.
191    * @exception SMIMEException if smtpHost or fromAddress parameters are null.
192    * Also, it can be caused by non SMIMEException which is MessagingException.
193    */

194   public SignedAndEnvelopedSMIME (String JavaDoc smtpHost, String JavaDoc fromAddress, String JavaDoc subject,
195                           String JavaDoc charset) throws SMIMEException
196   {
197     super(smtpHost, fromAddress, subject, null, charset);
198   }
199
200
201   /**
202    * Construction of message with external prepared MimeMessage object. Usage of
203    * this constructor disables usage of setContent() and addAttachment() methods.
204    * Also, all recipients (TO, CC or BCC type) must be declared again via
205    * setRecipient() method, even if they were previously set. Be very carefull
206    * with usage of this constructor because all MimeBodyPart objects and
207    * MimeMultipart objects used in construction of given MimeMessage object,
208    * must have correct defined Content header arguments, and contents. Contents
209    * must be formed in format which can be recognised and appropriate interpreted
210    * in the process of sending mail. If there is any special content object
211    * added to MimeBodyPart object or MimeMultipart object, the appropriate
212    * DataContent handler must be created for that object and set to corresponding
213    * BodyPart.
214    * @param mimeMessage external created MimeMessage object
215    * @exception SMIMEException if smtpHost or fromAddress parameter is null.
216    * Also, it can be caused by non SMIMEException which is MessagingException.
217    */

218   public SignedAndEnvelopedSMIME (MimeMessage JavaDoc mimeMessage) throws SMIMEException
219   {
220     super(mimeMessage);
221   }
222
223
224   /**
225    * Adds recipient address, type and .cer file of email recipient to signed and
226    * encrypted message. At least one recipient must be declared as TO type.
227    * @param recipientAddress email address of recipent (fields TO or CC or BCC
228    * in email message header)
229    * @param type should be TO, CC or BCC
230    * @param cerFileName path and file name with certificate corresponding
231    * to recipient (file with .cer extension)
232    * @exception SMIMEException if type of addressing of the messages is not TO, CC,
233    * or BCC. Also it can be caused by non SMIMEException which is MessagingException.
234    */

235   public void addRecipient (String JavaDoc recipientAddress, String JavaDoc type, String JavaDoc cerFileName)
236       throws SMIMEException
237   {
238     super.addRecipient(recipientAddress, type, cerFileName);
239   }
240
241
242   /**
243    * Adds recipient address, type and recipient's certificate via KeyStore
244    * object and apropriate alias. Certificate information should be passed only
245    * in the case of Enveloped message or Signed and Enveloped message. Otherwise
246    * those arguments represent redundance values and they should be given as
247    * null.
248    * @param recipientAddress email address of recipent (fields TO or CC or BCC
249    * in email message header)
250    * @param type should be TO, CC or BCC
251    * @param kStore instance of KeyStore class which represents an in-memory
252    * collection of keys and certificates.
253    * @param alias alias name which corresponds to desired certificate. If alias
254    * is given as null, then reading results are unpredictable.
255    * @exception SMIMEException if type of addressing of messages is not TO, CC
256    * or BCC. Also, it can be caused by non SMIMEException which can be one of
257    * the following: IOException, MessagingException, FileNotFoundException,
258    * NoSuchProviderException, CertificateException.
259    */

260   public void addRecipient (String JavaDoc recipientAddress, String JavaDoc type, KeyStore JavaDoc kStore, String JavaDoc alias)
261       throws SMIMEException
262   {
263     super.addRecipient(recipientAddress, type, kStore, alias);
264   }
265
266
267   /**
268    * Adds recipient address, type and recipient's certificate via path to the
269    * KeyStore file, KeyStore type, password and apropriate alias. Certificate
270    * information should be passed only in the case of Enveloped message or
271    * Signed and Enveloped message. Otherwise those arguments represent
272    * redundance values and they should be given as null.
273    * @param recipientAddress email address of recipent (fields TO or CC or BCC
274    * in email message header)
275    * @param type should be TO, CC or BCC
276    * @param ksPath is path to the file representation of KeyStore which holds
277    * collection of keys and certificates. This file can be PKCS12 type (file
278    * with .p12 or .pfx extension) or can be key store of other types readable
279    * by 'BouncyCastle' or 'Sun' KeyStore implementation.
280    * @param ksType is type of KeyStore. It can be one of the following types:
281    * JKS for 'Sun' KeyStore, 'BKS', 'PKCS12' or 'UBER') for 'BouncyCastle'
282    * KeyStore. If ksType is given as null it will be assumed that .cer file is
283    * in use, and alias parameter will be ignored, so this method becomes
284    * equivalent to addRecipient() method which deal only with .cer files.
285    * @param password password used to access the corresponding private key,
286    * stored in given KeyStore file.
287    * @param alias alias name which corresponds to desired private key. If alias
288    * is given as null, then reading results are unpredictable.
289    * to recipient (file with .cer extension)
290    * @exception SMIMEException if type of addressing of messages is not TO, CC
291    * or BCC. Also, it can be caused by non SMIMEException which can be one of
292    * the following: IOException, MessagingException, FileNotFoundException,
293    * NoSuchProviderException, CertificateException.
294    */

295   public void addRecipient (String JavaDoc recipientAddress, String JavaDoc type, String JavaDoc ksPath,
296                                String JavaDoc ksType, String JavaDoc password, String JavaDoc alias ) throws SMIMEException
297   {
298     super.addRecipient (recipientAddress, type, ksPath, ksType, password, alias );
299   }
300
301
302 /**
303  * Signes and envelopes message with default algorithm RC2, 40 bits.
304  * @param type defines which action will be performed first (signing or
305  * enveloping). Allowed parameters are: SIGN_FIRST (signing first and then
306  * enveloping), and ENCRYPT_FIRST (enveloping first and then signing).
307  * @exception SMIMEException if one of recipients is not declared as TO
308  * recipient, if there is no message for enveloping, or if parameter "type"
309  * for message protection order in not SIGN_FIRST or ENCRYPT_FIRST. Also, it
310  * can be caused by non SMIMEException which can be one of the following:
311  * CertificateException, IOException, MessagingException, or FileNotFoundException.
312  */

313   public void signingAndEnveloping (String JavaDoc type) throws SMIMEException
314   {
315     this.signingAndEnveloping("RC2_CBC", 40, type); // type can take values "SIGN_FIRST" or "ENCRYPT_FIRST"
316
}
317
318 /**
319  * Signes and envelopes message with given algorithm name and key length.
320  * @param algorithmName name of chosen algorithm used for encryption
321  * @param keyLength key size in bits
322  * @param type defines which action will be performed first (signing or
323  * enveloping). Allowed parameters are: SIGN_FIRST (signing first and then
324  * enveloping), and ENCRYPT_FIRST (enveloping first and then signing).
325  * @exception SMIMEException if one of recipients is not declared as TO
326  * recipient, if there is no message for enveloping or if parameter "type"
327  * for message protection order in not SIGN_FIRST or ENCRYPT_FIRST. Also, it
328  * can be caused by non SMIMEException which can be one of the following:
329  * CertificateException, IOException, MessagingException, or FileNotFoundException.
330  */

331   public void signingAndEnveloping (String JavaDoc algorithmName, int keyLength, String JavaDoc type) throws SMIMEException
332   {
333     try {
334       if ( (!type.equalsIgnoreCase("SIGN_FIRST")) && (!type.equalsIgnoreCase("ENCRYPT_FIRST")) )
335         throw new SMIMEException(this, 1046);
336
337       if (super.indicatorTo != true)
338         throw new SMIMEException(this, 1043);
339
340       if(!super.externalMessagePresence) { // external MimeMessage object presence cheking
341

342         if (super.contentPresence & super.bodyPartArray.size() == 1) { // message contains only content
343
if(super.bodyPartArray.elementAt(0) instanceof MimeBodyPart JavaDoc) { // text/plain message
344
MimeBodyPart JavaDoc contentBody = (MimeBodyPart JavaDoc)super.bodyPartArray.elementAt(0);
345             super.message.setContent((String JavaDoc)contentBody.getContent(), contentBody.getContentType());
346             super.message.setDisposition(super.message.INLINE);
347           }
348           else // text/html message
349
super.message.setContent((MimeMultipart JavaDoc)super.bodyPartArray.elementAt(0));
350         }
351         else if ( super.bodyPartArray.size() != 0) {
352           Multipart JavaDoc mp = new MimeMultipart JavaDoc();
353           for (int i = 0; i != super.bodyPartArray.size(); i++) {
354             if(super.bodyPartArray.elementAt(i) instanceof MimeMultipart JavaDoc) {
355               MimeBodyPart JavaDoc forMulti = new MimeBodyPart JavaDoc();
356               forMulti.setContent((MimeMultipart JavaDoc)super.bodyPartArray.elementAt(i));
357               mp.addBodyPart(forMulti);
358             }
359             else
360               mp.addBodyPart((MimeBodyPart JavaDoc)super.bodyPartArray.elementAt(i));
361           }
362           super.message.setContent(mp);
363         }
364         else
365           throw new SMIMEException(this, 1044);
366       }
367       CMSSignedDataSource sigDataSource = null;
368       CMSEnvelopedDataSource envDataSource = null;
369
370       if (type.equalsIgnoreCase("SIGN_FIRST")) {
371         sigDataSource = new CMSSignedDataSource(super.message, false);
372         for (int i = 0; i < super.ksArray.size(); i++) {
373           boolean[] incl = (boolean[])super.including.elementAt(i);
374           for (int j = 6*i; j != (6*(i + 1)) && super.capabilities.elementAt(j) != null; j = j + 2) {
375             int[] capabil = (int[])super.capabilities.elementAt(j + 1);
376             sigDataSource.setCapabilities((String JavaDoc)super.capabilities.elementAt(j), capabil[0], capabil[1], capabil[2], capabil[3], capabil[4]);
377           }
378           sigDataSource.addSigner((KeyStore JavaDoc)super.ksArray.elementAt(i), incl[0], incl[1], (String JavaDoc)super.digestArray.elementAt(i));
379         }
380         for (int i = 0; i < super.certChainArray.size(); i++) {
381           boolean[] incl2 = (boolean[])super.including2.elementAt(i);
382           for (int j = 6*i; j != (6*(i + 1)) && super.capabilities2.elementAt(j) != null; j = j + 2) {
383             int[] capabil = (int[])super.capabilities2.elementAt(j + 1);
384             sigDataSource.setCapabilities((String JavaDoc)super.capabilities2.elementAt(j), capabil[0], capabil[1], capabil[2], capabil[3], capabil[4]);
385           }
386           sigDataSource.addSigner((X509Certificate JavaDoc[])super.certChainArray.elementAt(i), (PrivateKey JavaDoc)super.privKeyArray.elementAt(i), incl2[0], incl2[1], (String JavaDoc)super.digestArray2.elementAt(i));
387         }
388         for (int i = 0; i < super.aditionalCerts.size(); i++) {
389           sigDataSource.addCertificate((X509Certificate JavaDoc)super.aditionalCerts.elementAt(i));
390         }
391
392         super.message.setDataHandler(new DataHandler JavaDoc(sigDataSource));
393         super.message.saveChanges();
394         envDataSource = new CMSEnvelopedDataSource(MimeAssist.messageConvertor(super.message),
395                                         algorithmName, keyLength);
396
397         for (int i = 0; i != super.certArray.size(); i++) {
398           X509Certificate JavaDoc cert = (X509Certificate JavaDoc)super.certArray.elementAt(i);
399           envDataSource.addRecipient(cert);
400         }
401         super.message.setDataHandler(new DataHandler JavaDoc(envDataSource));
402         super.message.saveChanges();
403         super.message.setDescription("Signed and Enveloped SMIME message.");
404       }
405       else {
406         envDataSource = new CMSEnvelopedDataSource(super.message, algorithmName, keyLength);
407         for (int i = 0; i != super.certArray.size(); i++) {
408           X509Certificate JavaDoc cert = (X509Certificate JavaDoc)super.certArray.elementAt(i);
409           envDataSource.addRecipient(cert);
410         }
411
412         super.message.setDataHandler(new DataHandler JavaDoc(envDataSource));
413         super.message.saveChanges();
414         sigDataSource = new CMSSignedDataSource(MimeAssist.messageConvertor(super.message),
415                                         false);
416
417         for (int i = 0; i < super.ksArray.size(); i++) {
418           boolean[] incl = (boolean[])super.including.elementAt(i);
419           for (int j = 6*i; j != (6*(i + 1)) && super.capabilities.elementAt(j) != null; j = j + 2) {
420             int[] capabil = (int[])super.capabilities.elementAt(j + 1);
421             sigDataSource.setCapabilities((String JavaDoc)super.capabilities.elementAt(j), capabil[0], capabil[1], capabil[2], capabil[3], capabil[4]);
422           }
423           sigDataSource.addSigner((KeyStore JavaDoc)super.ksArray.elementAt(i), incl[0], incl[1], (String JavaDoc)super.digestArray.elementAt(i));
424         }
425         for (int i = 0; i < super.certChainArray.size(); i++) {
426           boolean[] incl2 = (boolean[])super.including2.elementAt(i);
427           for (int j = 6*i; j != (6*(i + 1)) && super.capabilities2.elementAt(j) != null; j = j + 2) {
428             int[] capabil = (int[])super.capabilities2.elementAt(j + 1);
429             sigDataSource.setCapabilities((String JavaDoc)super.capabilities2.elementAt(j), capabil[0], capabil[1], capabil[2], capabil[3], capabil[4]);
430           }
431           sigDataSource.addSigner((X509Certificate JavaDoc[])super.certChainArray.elementAt(i), (PrivateKey JavaDoc)super.privKeyArray.elementAt(i), incl2[0], incl2[1], (String JavaDoc)super.digestArray2.elementAt(i));
432         }
433         for (int i = 0; i < super.aditionalCerts.size(); i++) {
434           sigDataSource.addCertificate((X509Certificate JavaDoc)super.aditionalCerts.elementAt(i));
435         }
436         super.message.setDataHandler(new DataHandler JavaDoc(sigDataSource));
437         super.message.saveChanges();
438         super.message.setDescription("Enveloped and Signed SMIME message.");
439       }
440
441       super.message.setDisposition(super.message.ATTACHMENT);
442       TimeZone JavaDoc tz = TimeZone.getDefault();
443       GregorianCalendar JavaDoc cal = new GregorianCalendar JavaDoc(tz);
444       super.message.setSentDate(cal.getTime());
445       clean();
446     }
447     catch (Exception JavaDoc e) {
448       throw SMIMEException.getInstance(this, e, "signingAndEnveloping");
449     }
450   }
451
452 /**
453  * Returns SMIME Message. This method returns same object as getMimeMessage()
454  * method located in super class and will be removed in future release.
455  * @deprecated
456  * @return Signed and encrypted (or encrypted and signed) S/MIME message.
457  */

458   public MimeMessage JavaDoc getSignedAndEnvelopedSMimeMessage () {
459     return super.message;
460   }
461
462
463 /**
464  * Releases unnecessary memory.
465  */

466   private void clean () {
467     super.reset();
468     System.gc(); // Calling garbage collector
469
}
470 }
471
472
473
474
Popular Tags