1 37 package net.sourceforge.cruisecontrol.publishers; 38 39 import java.util.Arrays ; 40 import java.util.HashSet ; 41 import java.util.Iterator ; 42 import java.util.Set ; 43 import java.util.StringTokenizer ; 44 45 import net.sourceforge.cruisecontrol.CruiseControlException; 46 import net.sourceforge.cruisecontrol.util.ValidationHelper; 47 import net.sourceforge.cruisecontrol.util.XMLLogHelper; 48 49 import org.apache.log4j.Logger; 50 51 import com.lotus.sametime.announcement.AnnouncementService; 52 import com.lotus.sametime.community.CommunityService; 53 import com.lotus.sametime.community.Login; 54 import com.lotus.sametime.community.LoginEvent; 55 import com.lotus.sametime.community.LoginListener; 56 import com.lotus.sametime.core.comparch.DuplicateObjectException; 57 import com.lotus.sametime.core.comparch.STSession; 58 import com.lotus.sametime.core.types.STGroup; 59 import com.lotus.sametime.core.types.STObject; 60 import com.lotus.sametime.core.types.STUser; 61 import com.lotus.sametime.lookup.GroupContentEvent; 62 import com.lotus.sametime.lookup.GroupContentGetter; 63 import com.lotus.sametime.lookup.GroupContentListener; 64 import com.lotus.sametime.lookup.LookupService; 65 import com.lotus.sametime.lookup.ResolveEvent; 66 import com.lotus.sametime.lookup.ResolveListener; 67 import com.lotus.sametime.lookup.Resolver; 68 69 75 public class SametimeAnnouncementPublisher extends LinkEmailPublisher 76 implements LoginListener, ResolveListener, GroupContentListener { 77 private static final Logger LOG = Logger.getLogger(SametimeAnnouncementPublisher.class); 78 79 public static final String RESOLVE_CONFLICTS_RECIPIENT = "recipient"; public static final String RESOLVE_CONFLICTS_IGNORE = "ignore"; 81 public static final String RESOLVE_CONFLICTS_WARN = "warn"; 82 public static final String RESOLVE_CONFLICTS_ERROR = "error"; 83 84 public static final String RESOLVE_FAIL_IGNORE = "ignore"; 85 public static final String RESOLVE_FAIL_WARN = "warn"; 86 public static final String RESOLVE_FAIL_ERROR = "error"; 88 public static final String QUERY_GROUP_CONTENT_FAIL_IGNORE = "ignore"; 89 public static final String QUERY_GROUP_CONTENT_FAIL_WARN = "warn"; 90 public static final String QUERY_GROUP_CONTENT_FAIL_ERROR = "error"; 92 94 private String community; 96 private boolean resolveUsers = true; 98 private boolean resolveGroups = true; 100 private boolean useGroupContent = true; 102 private String handleResolveConflicts = RESOLVE_CONFLICTS_RECIPIENT; 104 private String handleResolveFails = RESOLVE_FAIL_ERROR; 106 private String handleQueryGroupContentFails = QUERY_GROUP_CONTENT_FAIL_ERROR; 108 private int timeout = 10; 110 private int sleepMillis = 5; 112 113 115 private STSession session; 117 private CommunityService communityService; 118 private AnnouncementService announcementService; 119 private LookupService lookupService; 120 121 private Set usernamesToResolveSet; 123 private Login login; 125 private Set recipientUserSet = null; 127 private Set recipientGroupSet = null; 129 private Set resolvedNameSet = null; 131 private STObject[] groupContent = null; 133 private String resolveFailMessage = null; 136 private String resolveConflictMessage = null; 137 private String queryGroupContentFailMessage = null; 138 139 public String getHost() { 141 return this.getMailHost(); 142 } 143 144 public void setHost(String value) { 146 this.setMailHost(value); 147 } 148 149 public String getCommunity() { 150 return this.community; 151 } 152 153 public void setCommunity(String value) { 154 this.community = value; 155 } 156 157 public boolean isResolveUsers() { 158 return this.resolveUsers; 159 } 160 161 public void setResolveUsers(boolean value) { 162 this.resolveUsers = value; 163 } 164 165 public boolean isResolveGroups() { 166 return this.resolveGroups; 167 } 168 169 public void setResolveGroups(boolean value) { 170 this.resolveGroups = value; 171 } 172 173 public boolean isUseGroupContent() { 174 return this.useGroupContent; 175 } 176 177 public void setUseGroupContent(boolean value) { 178 this.useGroupContent = value; 179 } 180 181 public String getHandleQueryGroupContentFails() { 182 return this.handleQueryGroupContentFails; 183 } 184 185 public String getHandleResolveConflicts() { 186 return this.handleResolveConflicts; 187 } 188 189 public String getHandleResolveFails() { 190 return this.handleResolveFails; 191 } 192 193 public void setHandleQueryGroupContentFails(String string) { 194 this.handleQueryGroupContentFails = string; 195 } 196 197 public void setHandleResolveConflicts(String value) { 198 this.handleResolveConflicts = value; 199 } 200 201 public void setHandleResolveFails(String value) { 202 this.handleResolveFails = value; 203 } 204 205 public int getTimeout() { 206 return this.timeout; 207 } 208 209 private int getTimeoutMillis() { 210 return this.getTimeout() * 1000; 211 } 212 213 public int getSleepMillis() { 214 return sleepMillis; 215 } 216 217 public void setTimeout(int value) { 218 timeout = value; 219 } 220 221 public void setSleepMillis(int value) { 222 sleepMillis = value; 223 } 224 225 public String getReturnAddress() { 228 return ""; 229 } 230 231 public void validate() throws CruiseControlException { 232 ValidationHelper.assertIsSet(getHost(), "host", this.getClass()); 233 ValidationHelper.assertIsSet(getUsername(), "username", this.getClass()); 234 235 ensureInEqualsIgnoreCase(this.getHandleResolveFails(), "handleResolveFails", 236 new String [] {RESOLVE_FAIL_ERROR, RESOLVE_FAIL_WARN, RESOLVE_FAIL_WARN}); 237 238 ensureInEqualsIgnoreCase(this.getHandleResolveConflicts(), "handleResolveConflicts", 239 new String [] {RESOLVE_CONFLICTS_ERROR, RESOLVE_CONFLICTS_IGNORE, 240 RESOLVE_CONFLICTS_RECIPIENT, RESOLVE_CONFLICTS_WARN}); 241 242 ensureInEqualsIgnoreCase(this.getHandleQueryGroupContentFails(), "handleQueryGroupContentFails", 243 new String [] {QUERY_GROUP_CONTENT_FAIL_ERROR, QUERY_GROUP_CONTENT_FAIL_IGNORE, 244 QUERY_GROUP_CONTENT_FAIL_WARN}); 245 } 246 247 private static void ensureInEqualsIgnoreCase(String attribute, String attributeName, 248 String [] strings) throws CruiseControlException { 249 for (int i = 0; i < strings.length; i++) { 250 String string = strings[i]; 251 if (attribute.equalsIgnoreCase(string)) { 252 return; 253 } 254 } 255 StringBuffer buf = new StringBuffer ("'"); 256 buf.append(attributeName).append("' attribute invalid. - valid values are "); 257 for (int i = 0; i < strings.length; i++) { 258 if (i > 0) { 259 buf.append(" | "); 260 } 261 buf.append(strings[i]); 262 } 263 ValidationHelper.fail(buf.toString()); 264 } 265 266 protected String createMessage(XMLLogHelper logHelper) { 268 return this.getBuildResultsURL() == null ? null : super.createMessage(logHelper); 269 } 270 271 protected boolean sendMail(String toList, String subject, String message, boolean important) 274 throws CruiseControlException { 275 276 boolean announcementSent = false; 277 278 LOG.info("Sending sametime notifications."); 279 280 this.usernamesToResolveSet = new HashSet (); 282 for (StringTokenizer strtok = new StringTokenizer (toList, ","); strtok.hasMoreTokens(); ) { 283 String token = strtok.nextToken(); 284 this.usernamesToResolveSet.add(token.trim()); 285 } 286 287 try { 288 this.session = new STSession("CruiseControl build notification" + this); 289 } catch (DuplicateObjectException ex) { 290 throw new RuntimeException ("cannot create sametime session" + ex); 291 } 292 this.session.loadSemanticComponents(); 293 this.session.start(); 294 295 this.communityService = (CommunityService) session.getCompApi(CommunityService.COMP_NAME); 296 this.lookupService = (LookupService) session.getCompApi(LookupService.COMP_NAME); 297 this.announcementService = (AnnouncementService) session.getCompApi(AnnouncementService.COMP_NAME); 298 this.communityService.addLoginListener(this); 299 if (this.getPassword() != null) { 300 if (LOG.isDebugEnabled()) { 301 LOG.debug("loginByPassword(" + this.getHost() + ", " + this.getUsername() + ", ****, " 302 + this.getCommunity() + ")"); 303 } 304 this.communityService.loginByPassword(this.getHost(), this.getUsername(), this.getPassword(), 305 this.getCommunity()); 306 } else { 307 if (LOG.isDebugEnabled()) { 308 LOG.debug("loginAsAnon(" + this.getHost() + ", " + this.getUsername() 309 + this.getCommunity() + ")"); 310 } 311 this.communityService.loginAsAnon(this.getHost(), this.getUsername(), this.getCommunity()); } 313 314 this.communityService.disableAutomaticReconnect(); 316 317 boolean bored = false; 318 long waitStart = System.currentTimeMillis(); 319 while (!this.isLoggedIn() && !bored) { 320 try { 321 Thread.sleep(this.getSleepMillis()); 322 } catch (InterruptedException ex) { 323 throw new RuntimeException ("sleep interrupted: " + ex); 324 } 325 bored = System.currentTimeMillis() - waitStart > this.getTimeoutMillis(); 326 } 327 if (bored && !this.isLoggedIn()) { 328 throw new RuntimeException ("bored waiting for login"); 329 } 330 331 try { 332 this.resolve(); 333 334 if (this.isUseGroupContent()) { 335 this.getGroupContent(); 336 } else if (this.recipientGroupSet != null) { 337 this.recipientUserSet.addAll(this.recipientGroupSet); 338 } 339 340 if (LOG.isDebugEnabled()) { 341 LOG.debug("announce to: " + this.recipientUserSet); 342 } 343 String announcementMessage = message == null ? subject : subject + "\r\n" + message; 345 this.announcementService.sendAnnouncement((STObject[]) this.recipientUserSet.toArray( 346 new STObject[this.recipientUserSet.size()]), false, announcementMessage); 347 announcementSent = true; 348 } finally { 349 try { 350 this.communityService.logout(); 351 } finally { 352 try { 353 this.session.stop(); 354 } finally { 355 this.session.unloadSession(); 356 } 357 } 358 return announcementSent; 359 } 360 } 361 362 private void resolve() throws CruiseControlException { 363 Resolver resolver = lookupService.createResolver(false, false, this.isResolveUsers(), this.isResolveGroups()); 364 resolver.addResolveListener(this); 365 366 try { 367 this.recipientUserSet = new HashSet (); 368 this.recipientGroupSet = new HashSet (); 369 this.resolvedNameSet = new HashSet (); 370 371 if (LOG.isDebugEnabled()) { 372 LOG.debug("resolving: " + this.usernamesToResolveSet); 373 } 374 resolver.resolve( 375 (String []) this.usernamesToResolveSet.toArray(new String [this.usernamesToResolveSet.size()])); 376 377 boolean bored = false; 379 long waitStart = System.currentTimeMillis(); 380 while (!this.isResolvedAllUsersAndGroups() && !bored && !this.isResolveError()) { 381 try { 382 Thread.sleep(this.getSleepMillis()); 383 } catch (InterruptedException ex) { 384 throw new RuntimeException ("sleep interrupted: " + ex); 385 } 386 bored = System.currentTimeMillis() - waitStart > this.getTimeoutMillis(); 387 } 388 if (this.resolveFailMessage != null 389 && RESOLVE_FAIL_ERROR.equalsIgnoreCase(this.getHandleResolveFails())) { 390 throw new CruiseControlException(this.resolveFailMessage); 391 } 392 if (this.resolveConflictMessage != null 393 && RESOLVE_CONFLICTS_ERROR.equalsIgnoreCase(this.getHandleResolveConflicts())) { 394 throw new CruiseControlException(this.resolveConflictMessage); 395 } 396 if (bored && !this.isResolvedAllUsersAndGroups()) { 397 throw new CruiseControlException("bored waiting for user/group resolving"); 398 } 399 } finally { 400 resolver.removeResolveListener(this); 401 } 402 } 403 404 private boolean haveGroupContent() { 405 return this.groupContent != null; 406 } 407 408 private void getGroupContent() throws CruiseControlException { 410 if (this.recipientGroupSet == null) { 411 return; 412 } 413 GroupContentGetter groupContentGetter = this.lookupService.createGroupContentGetter(); 414 groupContentGetter.addGroupContentListener(this); 415 try { 416 for (Iterator i = this.recipientGroupSet.iterator(); i.hasNext(); ) { 417 this.groupContent = null; 418 STGroup group = (STGroup) i.next(); 419 groupContentGetter.queryGroupContent(group); 420 boolean bored = false; 422 long waitStart = System.currentTimeMillis(); 423 while (!this.haveGroupContent() && !bored && !this.isQueryGroupContentError()) { 424 try { 425 Thread.sleep(this.getSleepMillis()); 426 } catch (InterruptedException ex) { 427 throw new CruiseControlException("sleep interrupted: " + ex); 428 } 429 bored = System.currentTimeMillis() - waitStart > this.getTimeoutMillis(); 430 } 431 if (this.isQueryGroupContentError()) { 432 throw new CruiseControlException(this.queryGroupContentFailMessage); 433 } 434 if (bored && !this.haveGroupContent()) { 435 throw new CruiseControlException("bored waiting to get group content for " + group); 436 } 437 } 438 } finally { 439 groupContentGetter.removeGroupContentListener(this); 440 } 441 } 442 443 private synchronized boolean isQueryGroupContentError() { 444 return this.queryGroupContentFailMessage != null 445 && QUERY_GROUP_CONTENT_FAIL_ERROR.equalsIgnoreCase(this.getHandleQueryGroupContentFails()); 446 } 447 448 private synchronized boolean isLoggedIn() { 449 return this.communityService != null && this.communityService.isLoggedIn() && this.login != null; 450 } 451 452 private synchronized boolean isResolvedAllUsersAndGroups() { 454 if (this.usernamesToResolveSet == null) { 455 return true; 456 } 457 for (Iterator i = this.usernamesToResolveSet.iterator(); i.hasNext(); ) { 458 String username = (String ) i.next(); 459 if (!this.resolvedNameSet.contains(username.toLowerCase())) { 460 return false; 461 } 462 } 463 return true; 464 } 465 466 private synchronized boolean isResolveError() { 467 return this.resolveFailMessage != null 468 && RESOLVE_FAIL_ERROR.equalsIgnoreCase(this.getHandleResolveFails()) 469 || this.resolveConflictMessage != null 470 && RESOLVE_CONFLICTS_ERROR.equalsIgnoreCase(this.getHandleResolveConflicts()); 471 } 472 473 public synchronized void loggedIn(LoginEvent loginEvent) { 474 this.login = loginEvent.getLogin(); 475 } 476 477 public synchronized void loggedOut(LoginEvent arg0) { 478 this.login = null; 479 } 480 481 public synchronized void resolveConflict(ResolveEvent resolveEvent) { 482 STObject[] resolvedList = resolveEvent.getResolvedList(); 483 if (LOG.isDebugEnabled()) { 484 LOG.debug("resolve conflict: " + Arrays.asList(resolvedList)); 485 } 486 if (RESOLVE_CONFLICTS_RECIPIENT.equalsIgnoreCase(this.getHandleResolveConflicts())) { 487 if (resolvedList != null) { 488 for (int i = 0; i < resolvedList.length; i++) { 489 this.addRecipient(resolvedList[i]); 490 } 491 } 492 } else if (RESOLVE_CONFLICTS_ERROR.equalsIgnoreCase(this.getHandleResolveConflicts())) { 493 this.resolveConflictMessage = "resolveConflicts: " + Arrays.asList(resolvedList); 494 } else if (RESOLVE_CONFLICTS_WARN.equalsIgnoreCase(this.getHandleResolveConflicts())) { 495 LOG.warn("resolveConflicts: " + Arrays.asList(resolvedList)); 496 } 497 } 498 499 private synchronized void addRecipient(STObject recipient) { 500 this.resolvedNameSet.add(recipient.getName().toLowerCase()); 501 if (recipient instanceof STGroup) { 502 this.recipientGroupSet.add(recipient); 503 } else if (recipient instanceof STUser) { 504 this.recipientUserSet.add(recipient); 505 } 506 } 507 508 public synchronized void resolved(ResolveEvent resolveEvent) { 509 if (LOG.isDebugEnabled()) { 510 LOG.debug("resolved: " + resolveEvent.getResolved()); 511 } 512 this.addRecipient(resolveEvent.getResolved()); 513 } 514 515 public synchronized void resolveFailed(ResolveEvent resolveEvent) { 516 String [] failedNames = resolveEvent.getFailedNames(); 517 if (LOG.isDebugEnabled()) { 518 LOG.debug("resolve failed: " + Arrays.asList(failedNames)); 519 } 520 this.resolveFailMessage = "cannot resolve, reason " 521 + resolveEvent.getReason() + ": " + Arrays.asList(failedNames); 522 if (RESOLVE_FAIL_WARN.equalsIgnoreCase(this.getHandleResolveFails())) { 523 LOG.warn(this.resolveFailMessage); 524 } 525 } 526 527 public synchronized void groupContentQueried(GroupContentEvent groupContentEvent) { 528 STObject[] eventGroupContent = groupContentEvent.getGroupContent(); 529 if (eventGroupContent != null) { 530 for (int i = 0; i < eventGroupContent.length; i++) { 531 if (eventGroupContent[i] instanceof STUser) { 534 this.recipientUserSet.add(eventGroupContent[i]); 535 } else { 536 throw new UnsupportedOperationException ("groups within groups not supported - found subgroup " 537 + eventGroupContent[i].getName() + " while querying group " 538 + groupContentEvent.getGroup().getName()); 539 } 540 } 541 } 542 this.groupContent = eventGroupContent; 543 } 544 545 public synchronized void queryGroupContentFailed(GroupContentEvent groupContentEvent) { 546 this.queryGroupContentFailMessage = "queryGroupContent failed for group " 547 + groupContentEvent.getGroup().getName() 548 + ", reason " + groupContentEvent.getReason(); 549 if (QUERY_GROUP_CONTENT_FAIL_WARN.equalsIgnoreCase(this.getHandleQueryGroupContentFails())) { 550 LOG.warn(this.queryGroupContentFailMessage); 551 } 552 } 553 554 } 555 | Popular Tags |