1 17 18 package org.apache.james.transport; 19 20 import org.apache.avalon.framework.activity.Initializable; 21 import org.apache.avalon.framework.activity.Disposable; 22 import org.apache.avalon.framework.logger.AbstractLogEnabled; 23 import org.apache.avalon.framework.logger.Logger; 24 import org.apache.james.core.MailImpl; 25 import org.apache.james.core.MailetConfigImpl; 26 import org.apache.james.services.SpoolRepository; 27 import org.apache.mailet.*; 28 29 import javax.mail.MessagingException ; 30 import java.io.PrintWriter ; 31 import java.io.StringWriter ; 32 import java.util.ArrayList ; 33 import java.util.Collection ; 34 import java.util.List ; 35 import java.util.Random ; 36 import java.util.Iterator ; 37 import java.util.Locale ; 38 39 72 public class LinearProcessor 73 extends AbstractLogEnabled 74 implements Initializable, Disposable { 75 76 private static final Random random = new Random (); 78 85 private static final String TERMINATING_MATCHER_NAME = "Terminating%Matcher%Name"; 86 87 94 private static final String TERMINATING_MAILET_NAME = "Terminating%Mailet%Name"; 95 96 private List mailets; private List matchers; private volatile boolean listsClosed; private SpoolRepository spool; 101 108 public void setSpool(SpoolRepository spool) { 109 if (spool == null) { 110 throw new IllegalArgumentException ("The spool cannot be null"); 111 } 112 this.spool = spool; 113 } 114 115 118 public void initialize() { 119 matchers = new ArrayList (); 120 mailets = new ArrayList (); 121 } 122 123 133 public void dispose() { 134 Iterator it = mailets.iterator(); 135 boolean debugEnabled = getLogger().isDebugEnabled(); 136 while (it.hasNext()) { 137 Mailet mailet = (Mailet)it.next(); 138 if (debugEnabled) { 139 getLogger().debug("Shutdown mailet " + mailet.getMailetInfo()); 140 } 141 mailet.destroy(); 142 } 143 } 144 145 168 public synchronized void add(Matcher matcher, Mailet mailet) { 169 if (matcher == null) { 170 throw new IllegalArgumentException ("Null valued matcher passed to LinearProcessor."); 171 } 172 if (mailet == null) { 173 throw new IllegalArgumentException ("Null valued mailet passed to LinearProcessor."); 174 } 175 if (listsClosed) { 176 throw new IllegalStateException ("Attempt to add matcher/mailet after lists have been closed"); 177 } 178 matchers.add(matcher); 179 mailets.add(mailet); 180 } 181 182 190 public synchronized void closeProcessorLists() { 191 if (listsClosed) { 192 throw new IllegalStateException ("Processor's matcher/mailet lists have already been closed."); 193 } 194 Matcher terminatingMatcher = 195 new GenericMatcher() { 196 public Collection match(Mail mail) { 197 return mail.getRecipients(); 198 } 199 200 public String getMatcherInfo() { 201 return TERMINATING_MATCHER_NAME; 202 } 203 }; 204 Mailet terminatingMailet = 205 new GenericMailet() { 206 public void service(Mail mail) { 207 if (!(Mail.ERROR.equals(mail.getState()))) { 208 StringBuffer warnBuffer = new StringBuffer (256) 213 .append("Message ") 214 .append(((MailImpl)mail).getName()) 215 .append(" reached the end of this processor, and is automatically deleted. This may indicate a configuration error."); 216 LinearProcessor.this.getLogger().warn(warnBuffer.toString()); 217 } 218 mail.setState(Mail.GHOST); 219 } 220 221 public String getMailetInfo() { 222 return getMailetName(); 223 } 224 225 public String getMailetName() { 226 return TERMINATING_MAILET_NAME; 227 } 228 }; 229 add(terminatingMatcher, terminatingMailet); 230 listsClosed = true; 231 } 232 233 251 public void service(MailImpl mail) throws MessagingException { 252 if (spool == null) { 253 throw new IllegalStateException ("Attempt to service mail before the spool has been set to a non-null value"); 254 } 255 256 if (!listsClosed) { 257 throw new IllegalStateException ("Attempt to service mail before matcher/mailet lists have been closed"); 258 } 259 260 if (getLogger().isDebugEnabled()) { 261 getLogger().debug("Servicing mail: " + mail.getName()); 262 } 263 276 List [] unprocessed = new List [matchers.size() + 1]; 277 278 for (int i = 0; i < unprocessed.length; i++) { 279 unprocessed[i] = new ArrayList (); 282 } 283 284 unprocessed[0].add(mail); 286 287 String originalState = mail.getState(); 289 290 mail = null; int i = 0; while (true) { 294 unprocessed[unprocessed.length - 1].clear(); 308 309 mail = null; 311 312 for (i = 0; i < unprocessed.length; i++) { 314 if (unprocessed[i].size() > 0) { 315 mail = (MailImpl)unprocessed[i].remove(0); 317 break; 318 } 319 } 320 321 if (mail == null) { 323 return; 325 } 326 327 328 Collection recipients = null; 330 Matcher matcher = (Matcher) matchers.get(i); 331 StringBuffer logMessageBuffer = null; 332 if (getLogger().isDebugEnabled()) { 333 logMessageBuffer = 334 new StringBuffer (128) 335 .append("Checking ") 336 .append(mail.getName()) 337 .append(" with ") 338 .append(matcher); 339 getLogger().debug(logMessageBuffer.toString()); 340 } 341 try { 342 recipients = matcher.match(mail); 343 if (recipients == null) { 344 recipients = new ArrayList (0); 346 } else if (recipients != mail.getRecipients()) { 347 verifyMailAddresses(recipients); 349 } 350 } catch (MessagingException me) { 351 MailetConfig mailetConfig = ((Mailet) mailets.get(i)).getMailetConfig(); 353 String onMatchException = ((MailetConfigImpl) mailetConfig).getInitAttribute("onMatchException"); 354 if (onMatchException == null) { 355 onMatchException = Mail.ERROR; 356 } else { 357 onMatchException = onMatchException.trim().toLowerCase(Locale.US); 358 } 359 if (onMatchException.compareTo("nomatch") == 0) { 360 recipients = new ArrayList (0); 362 } else if (onMatchException.compareTo("matchall") == 0) { 363 recipients = mail.getRecipients(); 364 } else { 366 handleException(me, mail, matcher.getMatcherConfig().getMatcherName(), onMatchException); 367 } 368 } 369 370 Collection notRecipients; 373 if (recipients == mail.getRecipients() || recipients.size() == 0) { 374 notRecipients = new ArrayList (0); 375 } else { 376 notRecipients = new ArrayList (mail.getRecipients()); 377 notRecipients.removeAll(recipients); 378 } 379 380 if (recipients.size() == 0) { 381 unprocessed[i + 1].add(mail); 383 continue; 384 } 385 if (notRecipients.size() != 0) { 386 MailImpl notMail = (MailImpl)mail.duplicate(newName(mail)); 390 notMail.setRecipients(notRecipients); 391 unprocessed[i + 1].add(notMail); 392 mail.setRecipients(recipients); 394 } 395 Mailet mailet = (Mailet) mailets.get(i); 397 if (getLogger().isDebugEnabled()) { 398 logMessageBuffer = 399 new StringBuffer (128) 400 .append("Servicing ") 401 .append(mail.getName()) 402 .append(" by ") 403 .append(mailet.getMailetInfo()); 404 getLogger().debug(logMessageBuffer.toString()); 405 } 406 try { 407 mailet.service(mail); 408 verifyMailAddresses(mail.getRecipients()); 410 } catch (MessagingException me) { 411 MailetConfig mailetConfig = mailet.getMailetConfig(); 412 String onMailetException = ((MailetConfigImpl) mailetConfig).getInitAttribute("onMailetException"); 413 if (onMailetException == null) { 414 onMailetException = Mail.ERROR; 415 } else { 416 onMailetException = onMailetException.trim().toLowerCase(Locale.US); 417 } 418 if (onMailetException.compareTo("ignore") == 0) { 419 verifyMailAddresses(mail.getRecipients()); 422 } else { 423 handleException(me, mail, mailet.getMailetConfig().getMailetName(), onMailetException); 424 } 425 } 426 427 if (!mail.getState().equals(originalState)) { 429 if (mail.getState().equals(Mail.GHOST)) { 431 mail = null; 433 continue; 434 } 435 spool.store(mail); 439 mail = null; 440 continue; 441 } else { 442 unprocessed[i + 1].add(mail); 445 } 446 447 } 448 } 449 450 457 private String newName(MailImpl mail) { 458 StringBuffer nameBuffer = 459 new StringBuffer (64) 460 .append(mail.getName()) 461 .append("-!") 462 .append(random.nextInt(1048576)); 463 return nameBuffer.toString(); 464 } 465 466 467 468 473 private void verifyMailAddresses(Collection col) throws MessagingException { 474 try { 475 MailAddress addresses[] = (MailAddress[])col.toArray(new MailAddress[0]); 476 477 if (addresses.length != col.size()) { 481 throw new MailetException("The recipient list contains objects other than MailAddress objects"); 482 } 483 } catch (ArrayStoreException ase) { 484 throw new MailetException("The recipient list contains objects other than MailAddress objects"); 485 } 486 } 487 488 499 private void handleException(MessagingException me, Mail mail, String offendersName, String nextState) throws MessagingException { 500 System.err.println("exception! " + me); 501 mail.setState(nextState); 502 StringWriter sout = new StringWriter (); 503 PrintWriter out = new PrintWriter (sout, true); 504 StringBuffer exceptionBuffer = 505 new StringBuffer (128) 506 .append("Exception calling ") 507 .append(offendersName) 508 .append(": ") 509 .append(me.getMessage()); 510 out.println(exceptionBuffer.toString()); 511 Exception e = me; 512 while (e != null) { 513 e.printStackTrace(out); 514 if (e instanceof MessagingException ) { 515 e = ((MessagingException )e).getNextException(); 516 } else { 517 e = null; 518 } 519 } 520 String errorString = sout.toString(); 521 mail.setErrorMessage(errorString); 522 getLogger().error(errorString); 523 throw me; 524 } 525 } 526 | Popular Tags |