1 10 11 package org.mmbase.applications.community.builders; 12 13 import java.util.*; 14 import java.io.*; 15 16 import org.mmbase.module.core.*; 17 import org.mmbase.applications.community.modules.*; 18 import org.mmbase.util.*; 19 import org.mmbase.util.logging.*; 20 21 42 43 public class Channel extends MMObjectBuilder { 44 45 46 public static final int CLOSED = -1; 47 48 public static final int WANT_OPEN = 0; 49 50 public static final int READ_ONLY = 1; 51 52 public static final int OPEN = 2; 53 54 55 public static final int FAILED = -1; 56 57 public static final int CHANNEL_FULL = 0; 58 59 public static final int CONNECTED = 1; 60 61 public static final int ALREADY_CONNECTED = 2; 62 63 public static final int DISCONNECTED = 3; 64 65 66 public static final String F_OPEN = "open"; 67 68 public static final String F_MAXUSERS = "maxusers"; 69 70 public static final String F_STATE = "state"; 71 72 public static final String F_SESSION = "session"; 73 74 75 public static final String F_READLOGIN = "readlogin"; 76 77 public static final String F_WRITELOGIN = "writelogin"; 78 79 public static final String F_HASMOODS = "hasmoods"; 80 81 82 public static final int STATE_READ_LOGIN = 1; 83 84 public static final int STATE_WRITE_LOGIN = 2; 85 86 private static final String STR_OPEN = "open"; 89 private static final String STR_CLOSED = "closed"; 90 private static final String STR_READ_ONLY = "readonly"; 91 92 private static Logger log = Logging.getLoggerInstance(Channel.class.getName()); 94 95 private TemporaryNodeManager tmpNodeManager = null; 97 98 private Message messageBuilder; 100 private Community communityBuilder; 102 private int expireTime = 5 * 60 * 1000; 104 private NodeBreaker chatboxConnections = null; 106 private String tOwner = "system"; 108 private boolean active = false; 110 111 115 private Hashtable openChannels = new Hashtable(); 116 117 private Hashtable recorders = new Hashtable(); 119 private String baseRecordPath = null; 121 private String defaultrecordfile = "chat.log"; 123 private String defaultUserType = null; 125 126 129 public Channel() { 130 } 131 132 142 public boolean init() { 143 boolean result = super.init(); 144 baseRecordPath=getInitParameter("baserecordpath"); 146 if ((baseRecordPath!=null) && (baseRecordPath.length()!=0)) { 147 if (baseRecordPath.charAt(baseRecordPath.length()-1)!=File.separatorChar) { 148 baseRecordPath+=File.separator; 149 } 150 } 151 defaultUserType=getInitParameter("defaultusertype"); 152 if ((defaultUserType==null) || (defaultUserType.length()==0)){ 153 defaultUserType="chatter"; 154 } 155 156 activate(); 157 return result; 158 } 159 160 165 public boolean activate() { 166 if (!active) { 167 messageBuilder = (Message) mmb.getMMObject("message"); 169 communityBuilder = (Community) mmb.getMMObject("community"); 171 if (messageBuilder != null && communityBuilder != null) { 172 tmpNodeManager = new TemporaryNodeManager(mmb); 174 chatboxConnections = new NodeBreaker(2 * expireTime, tmpNodeManager); 176 active = true; 177 try { 178 String strOpenChannelsOnStartup = getInitParameter("open-channels-on-startup"); 180 boolean openChannelsOnStartup = !"false".equals(strOpenChannelsOnStartup); 181 if (openChannelsOnStartup) { 183 openChannels(); 184 } 185 } catch (Exception e) { 186 active = false; 188 } 189 } 190 } 191 return active; 192 } 193 194 198 199 private void openChannels() { 200 if (communityBuilder != null) { 201 communityBuilder.openAllCommunities(); 202 } 203 212 } 213 214 220 public boolean open(MMObjectNode channel) { 221 MMObjectNode community = communityParent(channel); 222 if (community==null) { 223 log.error("open(): Can't open channel " + channel.getNumber()+" : no relation with a community"); 224 return false; 225 } 226 return open(channel,community); 227 } 228 229 236 public boolean open(MMObjectNode channel, MMObjectNode community) { 237 Integer channelnr=new Integer (channel.getNumber()); 240 if (log.isDebugEnabled()) 241 log.debug("open(): Opening channel "+channelnr+" ("+channel.getValue("name")+")"); 242 243 channel.setValue(F_OPEN, OPEN); 244 int highestSequence = channel.getIntValue("highseq"); 245 boolean isChatBox = community.getStringValue("kind").equalsIgnoreCase(Community.STR_CHATBOX); 246 if (isChatBox) { 247 channel.setValue("highseq", -1); 249 } 250 if (channel.commit()) { 251 if (isChatBox) { 252 if (openChannels.get(channelnr) == null) { 253 openChannels.put(channelnr,new Integer (highestSequence)); 254 } 255 } 256 log.debug("open(): channel "+channelnr+" opened"); 257 return true; 258 } 259 log.error("open(): Can't open channel "+channelnr); 260 return false; 261 } 262 263 269 public boolean close(MMObjectNode channel) { 270 Integer channelnr=new Integer (channel.getNumber()); 271 if (channel.getIntValue(F_OPEN) != CLOSED) { 272 channel.setValue(F_OPEN, CLOSED); 273 Integer highseq = (Integer )openChannels.get(channelnr); 274 if (highseq != null) channel.setValue("highseq", highseq); 275 if (channel.commit()) { 276 log.debug("close(): channel "+channelnr+"("+channel.getValue("name")+") closed."); 277 openChannels.remove(channelnr); 278 return true; 279 } 280 log.error("close(): Can't close channel "+channelnr); 281 return false; 282 } 283 return true; 284 } 285 286 291 public boolean readonly(MMObjectNode channel) { 292 Integer channelnr=new Integer (channel.getNumber()); 293 if (channel.getIntValue(F_OPEN) != READ_ONLY) { 294 channel.setValue(F_OPEN, READ_ONLY); 295 if (channel.commit()) { 296 log.debug("close(): channel "+channelnr+"("+channel.getValue("name")+") made read only."); 297 return true; 298 } 299 log.error("close(): Can't make channel "+channelnr+" read only"); 300 return false; 301 } 302 return true; 303 } 304 305 311 public String isOpen(MMObjectNode channel) { 312 switch (channel.getIntValue(F_OPEN)) { 313 case OPEN: return STR_OPEN; 314 case READ_ONLY: return STR_READ_ONLY; 315 case CLOSED: return STR_CLOSED; 316 default: 317 log.warn("isOpen: the following channel has an invalid open value: " + 318 channel + " - assuming the channel is closed."); 319 return STR_CLOSED; 320 } 321 } 322 323 327 public int getNewSequence(MMObjectNode channel) { 328 int newHighseq; 329 Integer channelnr=new Integer (channel.getNumber()); 330 Integer highseqObj = (Integer )openChannels.get(channelnr); 331 if (highseqObj != null) { 332 newHighseq = highseqObj.intValue() + 1; 334 openChannels.put(channelnr, new Integer (newHighseq)); 335 return newHighseq; 336 } 337 newHighseq = channel.getIntValue("highseq") + 1; 339 channel.setValue("highseq", newHighseq); 340 if (channel.commit()) { 341 return newHighseq; 342 } 343 log.error("getnewSequence(): couldn't return a new sequence number, because couldn't commit channel node."); 344 return -1; 345 } 346 347 348 354 public void removeAllMessages(MMObjectNode channel) { 355 358 if (messageBuilder != null) { 359 for (Enumeration messages = mmb.getInsRel().getRelated(channel.getNumber(), messageBuilder.getNumber()); 360 messages.hasMoreElements();) { 361 messageBuilder.removeNode((MMObjectNode)messages.nextElement(), true); 362 } 363 } 364 } 365 366 373 public Writer getRecorder(int channel) { 374 return (Writer)recorders.get(new Integer (channel)); 375 } 376 377 383 public Writer startRecorder(int channel, Writer recorder) { 384 Writer writer=getRecorder(channel); 385 if (writer!=null) { 386 return writer; 387 } 388 recorders.put(new Integer (channel), recorder); 389 Date now= new Date(); 390 try { 391 recorder.write("Start recorder for channel "+channel+" at "+now+"\n"); 392 recorder.flush(); 393 } catch (IOException e) { 394 log.error(""+e); 395 } 396 return recorder; 397 } 398 399 405 public Writer startRecorder(int channel, String filepath) { 406 try { 407 return startRecorder(channel,new FileWriter(filepath,true)); 408 } catch(IOException e) { 409 log.error(""+e); 410 return null; 411 } 412 } 413 414 418 public void stopRecorder(int channel) { 419 Writer recorder=(Writer)recorders.get(new Integer (channel)); 420 if (recorder!=null) { 421 try { 422 recorder.flush(); 423 recorder.close(); 424 } catch(IOException e) { 425 log.error(""+e); 426 } 427 recorders.remove(new Integer (channel)); 428 } 429 } 430 431 438 private String getTemporaryNodeKey(MMObjectNode channel, MMObjectNode user) { 439 return "C"+channel.getNumber()+"U"+user.getNumber(); 440 } 441 442 454 public synchronized int join(MMObjectNode user, MMObjectNode channel) { 455 if (messageBuilder == null) { 457 log.error("No message builder : join failed"); 458 return FAILED; 459 } 460 String key=getTemporaryNodeKey(channel,user); 461 462 if (getTmpNode(key)!=null) { 463 return ALREADY_CONNECTED; 464 } 465 466 int maxusers = channel.getIntValue("maxusers"); 468 if (maxusers != -1) { 469 int usersCount = messageBuilder.getTemporaryRelated(channel, "users").size(); 470 if (usersCount >= maxusers) 471 return CHANNEL_FULL; 472 } 473 474 478 try { 479 String tmp = tmpNodeManager.createTmpRelationNode("related", tOwner,key, "realchannel", "realusers"); 480 MMObjectNode node = tmpNodeManager.getNode(tOwner, tmp); 481 tmpNodeManager.setObjectField(tOwner, tmp, "snumber", channel.getValue("number")); 482 tmpNodeManager.setObjectField(tOwner, tmp, "dnumber", user.getValue("number")); 483 chatboxConnections.add(tOwner+"_"+key, (new Long (System.currentTimeMillis() + expireTime)).longValue()); 488 }catch(Exception e) { 489 log.error("join(): Could not create temporary relations between between channel and user.\n" + e); 490 return FAILED; 491 } 492 493 495 499 MMObjectNode relatedChannel; 500 MMObjectNode community = communityParent(channel); 501 MMObjectNode relatedCommunity; 502 503 Enumeration relatedChannels = messageBuilder.getTemporaryRelated(user, "channel").elements(); 504 while (relatedChannels.hasMoreElements()) { 505 relatedChannel = (MMObjectNode)relatedChannels.nextElement(); 506 relatedCommunity = communityParent(relatedChannel); 507 if (relatedCommunity.getNumber() == community.getNumber()) 508 if (relatedChannel.getNumber() != channel.getNumber()) 509 logout(user, relatedChannel); 510 } 511 return CONNECTED; 512 } 513 514 523 public synchronized int logout(MMObjectNode user, MMObjectNode channel) { 524 return leave(user,channel); 525 } 526 527 535 public synchronized int leave(MMObjectNode user, MMObjectNode channel) { 536 chatboxConnections.remove(tOwner+"_"+getTemporaryNodeKey(channel,user)); 537 return DISCONNECTED; 538 } 539 540 547 public synchronized void userStillActive(MMObjectNode user, MMObjectNode channel) { 548 chatboxConnections.update(tOwner+"_"+getTemporaryNodeKey(channel,user), 549 System.currentTimeMillis() + expireTime); 550 } 551 552 566 public Vector getListUsers(StringTagger params) { 567 Vector relatedUsers = getNodeListUsers(params); 568 Vector fields = params.Values("FIELDS"); 570 params.setValue("ITEMS","" + fields.size()); 572 573 Vector result=new Vector(); 574 MMObjectNode relatedUser; 575 String field; 576 for (Iterator i=relatedUsers.iterator(); i.hasNext();) { 577 relatedUser = (MMObjectNode)i.next(); 578 for (Iterator j=fields.iterator(); j.hasNext(); ) { 579 field=(String )j.next(); 580 result.add(relatedUser.getStringValue(field)); 581 } 582 } 583 return result; 584 } 585 586 600 public Vector getNodeListUsers(Map params) { 601 Vector result = new Vector(); 602 String id = (String )params.get("CHANNEL"); 603 MMObjectNode node = getNode(id); 604 if ((node == null) || !(node.getBuilder() instanceof Channel)) { 605 log.debug("getListUsers(): no or incorrect channel specified"); 606 return result; 607 } 608 String usertype = (String )params.get("TYPE"); 609 if (usertype==null) usertype= defaultUserType; 610 611 int offset=0; 612 String tmp = (String )params.get("FROMCOUNT"); 613 if (tmp!=null) offset=Integer.parseInt(tmp); 614 int max=Integer.MAX_VALUE; 615 tmp = (String )params.get("MAXCOUNT"); 616 if (tmp!=null) max=Integer.parseInt(tmp); 617 618 627 Vector sortFields; 628 Vector sortDirs; 629 if (params instanceof StringTagger) { 630 sortFields = ((StringTagger)params).Values("SORTFIELDS"); 631 sortDirs = ((StringTagger)params).Values("SORTDIRS"); 632 } else { 633 sortFields = (Vector)params.get("SORTFIELDS"); 634 sortDirs = (Vector)params.get("SORTDIRS"); 635 } 636 637 NodeComparator compareUsers=null; 638 if (sortFields!=null) { 639 if (sortDirs == null) { 640 compareUsers = new NodeComparator(sortFields); 641 } else { 642 compareUsers = new NodeComparator(sortFields, sortDirs); 643 } 644 } 645 return getListUsers(node, usertype, compareUsers,offset, max); 646 } 647 648 public void setDefaults(MMObjectNode node) { 650 node.setValue(F_OPEN, OPEN); 651 node.setValue(F_STATE, 0); 652 } 653 654 655 656 664 public Vector getListUsers(MMObjectNode channel, String usertype, 665 Comparator compareUsers, int offset, int max) { 666 Vector relatedUsers = messageBuilder.getTemporaryRelated(channel,usertype,offset,max); 667 if (compareUsers!=null) { 668 Collections.sort(relatedUsers,compareUsers); 669 } 670 return relatedUsers; 671 } 672 673 680 public MMObjectNode communityParent(MMObjectNode channel) { 681 if (communityBuilder != null) { 685 int oType = communityBuilder.getNumber(); 686 if (oType == 0) oType = mmb.getTypeDef().getIntValue("community"); 687 Enumeration relatedCommunity = mmb.getInsRel().getRelated(channel.getNumber(), oType); 688 if (relatedCommunity.hasMoreElements()) { 689 return (MMObjectNode)relatedCommunity.nextElement(); 690 } 691 } 692 return null; 693 } 694 695 722 public Object getValue(MMObjectNode node, String field) { 723 if (field.equals(Message.F_REPLY_COUNT)) { 726 return new Integer (messageBuilder.getNrMsgAndHighSeq(node).messageCount); 727 } 728 729 if (field.equals(F_READLOGIN)) { 730 return Boolean.valueOf((node.getIntValue(F_STATE) & STATE_READ_LOGIN)>0); 731 } 732 if (field.equals(F_WRITELOGIN)) { 733 return Boolean.valueOf((node.getIntValue(F_STATE) & STATE_WRITE_LOGIN)>0); 734 } 735 if (field.equals(F_HASMOODS)) { 736 if (node.getRelationCount("mood")>0) return "yes"; else return "no"; 737 } 738 return super.getValue(node, field); 739 } 740 741 749 protected Object executeFunction(MMObjectNode node,String function,String field) { 750 if (function.equals(F_HASMOODS)) { 751 return Boolean.valueOf(node.getRelationCount("mood")>0); 752 } else { 753 return super.executeFunction(node,function,field); 754 } 755 } 756 757 775 public String replace(PageInfo sp, StringTokenizer tok) { 776 if (!tok.hasMoreElements()) { 778 log.error("replace(): channel number expected after $MOD-BUILDER-channel-."); 779 return ""; 780 } 781 782 MMObjectNode channel = getNode(tok.nextToken()); 783 784 if (tok.hasMoreElements()) { 785 String cmd = tok.nextToken(); 786 if (cmd.equals("RECORD")) { 790 if (tok.hasMoreElements()) { 791 cmd = tok.nextToken(); 792 if (cmd.equals("STOP")) { 793 stopRecorder(channel.getNumber()); 794 } else if (cmd.equals("FILE")) { 795 if (tok.hasMoreElements()) { 796 cmd=tok.nextToken(); 797 } else { 798 cmd=defaultrecordfile; 799 } 800 if (baseRecordPath==null) { 801 log.error("Base recording filepath not specified - cannot record this channel."); 802 return ""; 803 } 804 String filename = baseRecordPath+cmd; 805 startRecorder(channel.getNumber(),filename); 806 } 807 return ""; 808 } 809 } 810 811 if (cmd.equals("OPEN")) open(channel); 812 if (cmd.equals("READONLY")) readonly(channel); 813 if (cmd.equals("CLOSE")) close(channel); 814 if (cmd.equals("ISOPEN")) return isOpen(channel); 815 if (cmd.equals("DELALLMESSAGES")) removeAllMessages(channel); 816 if (cmd.equals("NEWSEQ")) return "" + getNewSequence(channel); 817 if (cmd.equals("JOIN")) 818 join(getNode(tok.nextToken()), channel); 819 if (cmd.equals("LEAVE") || cmd.equals("QUIT")) 820 leave(getNode(tok.nextToken()), channel); 821 if (cmd.equals("STILLACTIVE")) { 822 userStillActive(getNode(tok.nextToken()), channel); 823 log.debug("replace(): user still active") ; 824 } 825 } 826 return ""; 827 } 828 829 832 public String getDefaultUrl(int src) { 833 if (communityBuilder != null) { 834 Enumeration e = mmb.getInsRel().getRelated(src, communityBuilder.getNumber()); 835 if (!e.hasMoreElements()) { 836 log.warn("GetDefaultURL Could not find related community for channel node " + src); 837 return null; 838 } 839 MMObjectNode commNode = (MMObjectNode)e.nextElement(); 840 String url = commNode.getBuilder().getDefaultUrl(commNode.getNumber()); 841 if (url != null) url += "+" + src; 842 return url; 843 } else { 844 return null; 845 } 846 } 847 848 856 public String getGUIIndicator(String field, MMObjectNode node) { 857 863 if (field.equals(F_SESSION)) { 864 int value = node.getIntValue(field); 865 if (value == 1) return "yes"; else return "no"; 866 } 867 if (field.equals(F_STATE)) { int value = node.getIntValue(field); 869 if ((value & STATE_READ_LOGIN) >0) 870 return "login before read"; 871 else if ((value & STATE_WRITE_LOGIN) > 0) 872 return "login before post"; 873 else return "no login"; 874 } 875 if (field.equals(F_OPEN)) { 876 return isOpen(node); 877 } 878 if (field.equals(F_MAXUSERS)) { 879 if (node.getIntValue(field)==-1) return "unlimited"; 880 } 881 return null; 882 } 883 884 } 885 | Popular Tags |