You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@esme.apache.org by dp...@apache.org on 2008/12/12 19:32:22 UTC
svn commit: r726084 [1/6] - in /incubator/esme/trunk/server: ./ src/
src/main/ src/main/resources/ src/main/resources/props/ src/main/scala/
src/main/scala/bootstrap/ src/main/scala/bootstrap/liftweb/
src/main/scala/us/ src/main/scala/us/esme/ src/main...
Author: dpp
Date: Fri Dec 12 10:32:17 2008
New Revision: 726084
URL: http://svn.apache.org/viewvc?rev=726084&view=rev
Log:
Initial server commit
Added:
incubator/esme/trunk/server/
incubator/esme/trunk/server/pom.xml
incubator/esme/trunk/server/src/
incubator/esme/trunk/server/src/main/
incubator/esme/trunk/server/src/main/resources/
incubator/esme/trunk/server/src/main/resources/props/
incubator/esme/trunk/server/src/main/resources/props/compass.cfg.xml
incubator/esme/trunk/server/src/main/resources/props/dpp.props
incubator/esme/trunk/server/src/main/resources/props/project.props
incubator/esme/trunk/server/src/main/resources/props/sapservicec71.props
incubator/esme/trunk/server/src/main/scala/
incubator/esme/trunk/server/src/main/scala/bootstrap/
incubator/esme/trunk/server/src/main/scala/bootstrap/liftweb/
incubator/esme/trunk/server/src/main/scala/bootstrap/liftweb/Boot.scala
incubator/esme/trunk/server/src/main/scala/us/
incubator/esme/trunk/server/src/main/scala/us/esme/
incubator/esme/trunk/server/src/main/scala/us/esme/actor/
incubator/esme/trunk/server/src/main/scala/us/esme/actor/Distributor.scala
incubator/esme/trunk/server/src/main/scala/us/esme/actor/GroupActor.scala
incubator/esme/trunk/server/src/main/scala/us/esme/actor/HttpSender.scala
incubator/esme/trunk/server/src/main/scala/us/esme/actor/MessagePullActor.scala
incubator/esme/trunk/server/src/main/scala/us/esme/actor/UserActor.scala
incubator/esme/trunk/server/src/main/scala/us/esme/api/
incubator/esme/trunk/server/src/main/scala/us/esme/api/RestAPI.scala
incubator/esme/trunk/server/src/main/scala/us/esme/comet/
incubator/esme/trunk/server/src/main/scala/us/esme/comet/.keep
incubator/esme/trunk/server/src/main/scala/us/esme/comet/PublicTimeline.scala
incubator/esme/trunk/server/src/main/scala/us/esme/comet/TagCloud.scala
incubator/esme/trunk/server/src/main/scala/us/esme/comet/Timeline.scala
incubator/esme/trunk/server/src/main/scala/us/esme/external/
incubator/esme/trunk/server/src/main/scala/us/esme/external/TwitterFeed.scala
incubator/esme/trunk/server/src/main/scala/us/esme/lib/
incubator/esme/trunk/server/src/main/scala/us/esme/lib/MsgFormat.scala
incubator/esme/trunk/server/src/main/scala/us/esme/lib/MsgParser.scala
incubator/esme/trunk/server/src/main/scala/us/esme/lib/TagUtils.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/
incubator/esme/trunk/server/src/main/scala/us/esme/model/.keep
incubator/esme/trunk/server/src/main/scala/us/esme/model/Action.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/AuthToken.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/DidPerform.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/ExtSession.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/Group.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/Mailbox.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/Message.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/MessageTag.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/Relationship.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/Tag.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/Tracking.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/UrlStore.scala
incubator/esme/trunk/server/src/main/scala/us/esme/model/User.scala
incubator/esme/trunk/server/src/main/scala/us/esme/snippet/
incubator/esme/trunk/server/src/main/scala/us/esme/snippet/.keep
incubator/esme/trunk/server/src/main/scala/us/esme/snippet/Style.scala
incubator/esme/trunk/server/src/main/scala/us/esme/snippet/UserSnip.scala
incubator/esme/trunk/server/src/main/scala/us/esme/view/
incubator/esme/trunk/server/src/main/scala/us/esme/view/.keep
incubator/esme/trunk/server/src/main/scala/us/esme/view/ActionView.scala
incubator/esme/trunk/server/src/main/scala/us/esme/view/Auth.scala
incubator/esme/trunk/server/src/main/scala/us/esme/view/Track.scala
incubator/esme/trunk/server/src/main/scala/us/esme/view/UserView.scala
incubator/esme/trunk/server/src/main/webapp/
incubator/esme/trunk/server/src/main/webapp/WEB-INF/
incubator/esme/trunk/server/src/main/webapp/WEB-INF/web.xml
incubator/esme/trunk/server/src/main/webapp/images/
incubator/esme/trunk/server/src/main/webapp/images/bg-i.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/bg-left.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/bg-m.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/bg-right.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/bg-right1.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/bg-t.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/btn-send-m.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/btn-sign-in.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/esme-blue.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/esme.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/img-1.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/mail.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/send-message.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/sh-a.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/sh-b.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/sh-r.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/sh-t.png (with props)
incubator/esme/trunk/server/src/main/webapp/images/sign-on.png (with props)
incubator/esme/trunk/server/src/main/webapp/index.html
incubator/esme/trunk/server/src/main/webapp/scripts/
incubator/esme/trunk/server/src/main/webapp/scripts/countdown_timer.js
incubator/esme/trunk/server/src/main/webapp/scripts/jquery-baf.js
incubator/esme/trunk/server/src/main/webapp/scripts/jquery-cur.min.js
incubator/esme/trunk/server/src/main/webapp/scripts/jquery.blockUI.js
incubator/esme/trunk/server/src/main/webapp/scripts/jquery.dimensions.js
incubator/esme/trunk/server/src/main/webapp/scripts/jquery.tooltips.js
incubator/esme/trunk/server/src/main/webapp/scripts/json2.js
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon.js
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/b.gif (with props)
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/background.gif (with props)
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/l.gif (with props)
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/lb.gif (with props)
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/lt.gif (with props)
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/r.gif (with props)
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/rb.gif (with props)
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/rt.gif (with props)
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/stemb.gif (with props)
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/stemt.gif (with props)
incubator/esme/trunk/server/src/main/webapp/scripts/tip_balloon/t.gif (with props)
incubator/esme/trunk/server/src/main/webapp/scripts/tip_centerwindow.js
incubator/esme/trunk/server/src/main/webapp/scripts/tip_followscroll.js
incubator/esme/trunk/server/src/main/webapp/scripts/ui.accordion.js
incubator/esme/trunk/server/src/main/webapp/scripts/ui.dialog.js
incubator/esme/trunk/server/src/main/webapp/scripts/ui.draggable.js
incubator/esme/trunk/server/src/main/webapp/scripts/ui.mouse.js
incubator/esme/trunk/server/src/main/webapp/scripts/ui.resizable.js
incubator/esme/trunk/server/src/main/webapp/scripts/ui.tabs.js
incubator/esme/trunk/server/src/main/webapp/scripts/wz_tooltip.js
incubator/esme/trunk/server/src/main/webapp/static/
incubator/esme/trunk/server/src/main/webapp/static/about.html
incubator/esme/trunk/server/src/main/webapp/style/
incubator/esme/trunk/server/src/main/webapp/style/b-back.css
incubator/esme/trunk/server/src/main/webapp/style/b-content.css
incubator/esme/trunk/server/src/main/webapp/style/b-edit.css
incubator/esme/trunk/server/src/main/webapp/style/b-list-ie.css
incubator/esme/trunk/server/src/main/webapp/style/b-list.css
incubator/esme/trunk/server/src/main/webapp/style/b-menu.css
incubator/esme/trunk/server/src/main/webapp/style/b-open.css
incubator/esme/trunk/server/src/main/webapp/style/b-popup-c.css
incubator/esme/trunk/server/src/main/webapp/style/b-popup-ie.css
incubator/esme/trunk/server/src/main/webapp/style/b-popup.css
incubator/esme/trunk/server/src/main/webapp/style/b-primary.css
incubator/esme/trunk/server/src/main/webapp/style/b-sign-on.css
incubator/esme/trunk/server/src/main/webapp/style/b-view-ie.css
incubator/esme/trunk/server/src/main/webapp/style/b-view-menu.css
incubator/esme/trunk/server/src/main/webapp/style/b-view.css
incubator/esme/trunk/server/src/main/webapp/style/esme-ie.css
incubator/esme/trunk/server/src/main/webapp/style/esme.css
incubator/esme/trunk/server/src/main/webapp/style/flora/
incubator/esme/trunk/server/src/main/webapp/style/flora/flora.accordion.css
incubator/esme/trunk/server/src/main/webapp/style/flora/flora.all.css
incubator/esme/trunk/server/src/main/webapp/style/flora/flora.calendar.css
incubator/esme/trunk/server/src/main/webapp/style/flora/flora.css
incubator/esme/trunk/server/src/main/webapp/style/flora/flora.dialog.css
incubator/esme/trunk/server/src/main/webapp/style/flora/flora.menu.css
incubator/esme/trunk/server/src/main/webapp/style/flora/flora.resizable.css
incubator/esme/trunk/server/src/main/webapp/style/flora/flora.shadow.css
incubator/esme/trunk/server/src/main/webapp/style/flora/flora.slider.css
incubator/esme/trunk/server/src/main/webapp/style/flora/flora.tablesorter.css
incubator/esme/trunk/server/src/main/webapp/style/flora/flora.tabs.css
incubator/esme/trunk/server/src/main/webapp/style/flora/i/
incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-left-act.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-left-over.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-left.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-middle-act.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-middle-over.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-middle.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-right-act.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-right-over.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/accordion-right.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/asc.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/bg.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/desc.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-e.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-n.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-ne.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-nw.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-s.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-se.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-sw.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-title.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-titlebar-close-hover.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-titlebar-close.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/dialog-w.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/menu-submenu.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-e.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-n.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-ne.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-nw.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-s.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-se.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-sw.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/resizable-w.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/shadow.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/slider-bg-1.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/slider-bg-2.png (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/slider-handle.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/flora/i/tabs.gif (with props)
incubator/esme/trunk/server/src/main/webapp/style/l-page-content.css
incubator/esme/trunk/server/src/main/webapp/style/l-page-login.css
incubator/esme/trunk/server/src/main/webapp/style/l-page-message.css
incubator/esme/trunk/server/src/main/webapp/style/l-page.css
incubator/esme/trunk/server/src/main/webapp/style/l-top-ie.css
incubator/esme/trunk/server/src/main/webapp/style/l-top.css
incubator/esme/trunk/server/src/main/webapp/style/layout.css
incubator/esme/trunk/server/src/main/webapp/style/print-ie.css
incubator/esme/trunk/server/src/main/webapp/style/print.css
incubator/esme/trunk/server/src/main/webapp/style/ui.tabs.css
incubator/esme/trunk/server/src/main/webapp/templates-hidden/
incubator/esme/trunk/server/src/main/webapp/templates-hidden/default.html
incubator/esme/trunk/server/src/main/webapp/templates-hidden/login.html
incubator/esme/trunk/server/src/main/webapp/templates-hidden/menu_footer.html
incubator/esme/trunk/server/src/main/webapp/templates-hidden/message.html
incubator/esme/trunk/server/src/test/
incubator/esme/trunk/server/src/test/scala/
incubator/esme/trunk/server/src/test/scala/LiftConsole.scala
incubator/esme/trunk/server/src/test/scala/RunWebApp.scala
incubator/esme/trunk/server/src/test/scala/us/
incubator/esme/trunk/server/src/test/scala/us/esme/
incubator/esme/trunk/server/src/test/scala/us/esme/AppTest.scala
incubator/esme/trunk/server/src/test/scala/us/esme/lib/
incubator/esme/trunk/server/src/test/scala/us/esme/lib/MsgParseTest.scala
Added: incubator/esme/trunk/server/pom.xml
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/pom.xml?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/pom.xml (added)
+++ incubator/esme/trunk/server/pom.xml Fri Dec 12 10:32:17 2008
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>us.esme</groupId>
+ <artifactId>esme</artifactId>
+ <version>0.2.3-SNAPSHOT</version>
+ <packaging>war</packaging>
+ <name>ESME</name>
+ <inceptionYear>2008</inceptionYear>
+ <properties>
+ <scala.version>2.7.2</scala.version>
+ <lucene.version>2.3.2</lucene.version>
+ <netbeans.hint.deploy.server>gfv3</netbeans.hint.deploy.server>
+ </properties>
+
+ <repositories>
+ <repository>
+ <id>scala-tools.org</id>
+ <name>Scala-Tools Maven2 Repository</name>
+ <url>http://scala-tools.org/repo-releases</url>
+ </repository>
+ <repository>
+ <id>scala-tools.org.snapshots</id>
+ <name>Scala-Tools Maven2 Repository for Snapshots</name>
+ <url>http://scala-tools.org/repo-snapshots</url>
+ <snapshots />
+ </repository>
+ <repository>
+ <id>compass-project.org</id>
+ <name>Compass</name>
+ <url>http://repo.compass-project.org</url>
+ </repository>
+ </repositories>
+
+ <pluginRepositories>
+ <pluginRepository>
+ <id>scala-tools.org</id>
+ <name>Scala-Tools Maven2 Repository</name>
+ <url>http://scala-tools.org/repo-releases</url>
+ </pluginRepository>
+ </pluginRepositories>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-library</artifactId>
+ <version>${scala.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.liftweb</groupId>
+ <artifactId>lift-core</artifactId>
+ <version>0.10-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>net.liftweb</groupId>
+ <artifactId>lift-testkit</artifactId>
+ <version>0.10-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>net.liftweb</groupId>
+ <artifactId>lift-openid</artifactId>
+ <version>0.10-SNAPSHOT</version>
+ </dependency>
+ <!--
+ <dependency>
+ <groupId>com.socialmaterial</groupId>
+ <artifactId>social</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ </dependency>
+ -->
+ <dependency>
+ <groupId>org.compass-project</groupId>
+ <artifactId>compass</artifactId>
+ <version>2.0.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>postgresql</groupId>
+ <artifactId>postgresql</artifactId>
+ <version>8.2-507.jdbc3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ <version>10.2.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>cglib</groupId>
+ <artifactId>cglib</artifactId>
+ <version>2.1_3</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.objenesis</groupId>
+ <artifactId>objenesis</artifactId>
+ <version>1.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.sourceforge.jwebunit</groupId>
+ <artifactId>jwebunit-htmlunit-plugin</artifactId>
+ <version>1.4.1</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty</artifactId>
+ <version>[6.1.6,)</version>
+ <scope>test</scope>
+ </dependency>
+ <!-- for LiftConsole -->
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-compiler</artifactId>
+ <version>${scala.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.lucene</groupId>
+ <artifactId>lucene-snowball</artifactId>
+ <version>${lucene.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.specs</groupId>
+ <artifactId>specs</artifactId>
+ <version>1.3.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <sourceDirectory>src/main/scala</sourceDirectory>
+ <testSourceDirectory>src/test/scala</testSourceDirectory>
+
+ <plugins>
+ <plugin>
+ <groupId>org.scala-tools</groupId>
+ <artifactId>maven-scala-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>compile</goal>
+ <goal>testCompile</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <scalaVersion>${scala.version}</scalaVersion>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>maven-jetty-plugin</artifactId>
+ <configuration>
+ <contextPath>/</contextPath>
+ <scanIntervalSeconds>0</scanIntervalSeconds>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>net.sf.alchim</groupId>
+ <artifactId>yuicompressor-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>compress</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <nosuffix>true</nosuffix>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-eclipse-plugin</artifactId>
+ <configuration>
+ <downloadSources>true</downloadSources>
+ <excludes>
+ <exclude>org.scala-lang:scala-library</exclude>
+ </excludes>
+ <classpathContainers>
+ <classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer>
+ </classpathContainers>
+ <projectnatures>
+ <java.lang.String>ch.epfl.lamp.sdt.core.scalanature</java.lang.String>
+ <java.lang.String>org.eclipse.jdt.core.javanature</java.lang.String>
+ </projectnatures>
+ <buildcommands>
+ <java.lang.String>ch.epfl.lamp.sdt.core.scalabuilder</java.lang.String>
+ </buildcommands>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.scala-tools</groupId>
+ <artifactId>maven-scala-plugin</artifactId>
+ <configuration>
+ <scalaVersion>${scala.version}</scalaVersion>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
Added: incubator/esme/trunk/server/src/main/resources/props/compass.cfg.xml
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/resources/props/compass.cfg.xml?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/resources/props/compass.cfg.xml (added)
+++ incubator/esme/trunk/server/src/main/resources/props/compass.cfg.xml Fri Dec 12 10:32:17 2008
@@ -0,0 +1,31 @@
+
+<compass-core-config xmlns="http://www.compass-project.org/schema/core-config"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.compass-project.org/schema/core-config
+ http://www.compass-project.org/schema/compass-core-config-2.0.xsd">
+
+ <compass name="default">
+
+ <connection>
+ <file path="compass-index"/>
+ </connection>
+ <searchEngine >
+ <analyzer name="default" type="Stop" />
+ <analyzer name="tag" type="Standard" />
+ <analyzer name="stemming" type="Snowball" snowballType="English">
+ <stopWords>
+ <stopWord value="no" />
+ <stopWord value="the" />
+ <stopWord value="and" />
+ <stopWord value="a" />
+ <stopWord value="this" />
+ <stopWord value="i" />
+ <stopWord value="is" />
+ </stopWords>
+ </analyzer>
+
+ </searchEngine>
+
+ </compass>
+
+</compass-core-config>
Added: incubator/esme/trunk/server/src/main/resources/props/dpp.props
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/resources/props/dpp.props?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/resources/props/dpp.props (added)
+++ incubator/esme/trunk/server/src/main/resources/props/dpp.props Fri Dec 12 10:32:17 2008
@@ -0,0 +1 @@
+use_local_psql=true
Added: incubator/esme/trunk/server/src/main/resources/props/project.props
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/resources/props/project.props?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/resources/props/project.props (added)
+++ incubator/esme/trunk/server/src/main/resources/props/project.props Fri Dec 12 10:32:17 2008
@@ -0,0 +1,4 @@
+# Properties file for COIL servers (user id = project)
+http.proxyHost=vsvGW000.pal.coil
+http.proxyPort=8080
+http.nonProxyHosts=*.sap.corp
Added: incubator/esme/trunk/server/src/main/resources/props/sapservicec71.props
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/resources/props/sapservicec71.props?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/resources/props/sapservicec71.props (added)
+++ incubator/esme/trunk/server/src/main/resources/props/sapservicec71.props Fri Dec 12 10:32:17 2008
@@ -0,0 +1,4 @@
+# Properties file for COIL servers (user id = project)
+http.proxyHost=vsvGW000.pal.coil
+http.proxyPort=8080
+http.nonProxyHosts=*.sap.corp
Added: incubator/esme/trunk/server/src/main/scala/bootstrap/liftweb/Boot.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/bootstrap/liftweb/Boot.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/bootstrap/liftweb/Boot.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/bootstrap/liftweb/Boot.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,213 @@
+package bootstrap.liftweb
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+import net.liftweb.util._
+import net.liftweb.http._
+import net.liftweb.sitemap._
+import net.liftweb.sitemap.Loc._
+import Helpers._
+import net.liftweb.mapper.{DB, ConnectionManager, Schemifier, DefaultConnectionIdentifier, ConnectionIdentifier}
+import java.sql.{Connection, DriverManager}
+import us.esme._
+import model._
+import actor._
+import lib._
+import view._
+import api._
+import net.liftweb._
+import mapper._
+import javax.servlet.http.{HttpServlet, HttpServletRequest , HttpServletResponse, HttpSession}
+import org.compass.core._
+import org.compass.core.config.CompassConfiguration
+
+/**
+ * A class that's instantiated early and run. It allows the application
+ * to modify lift's environment
+ */
+class Boot {
+ def boot {
+ DefaultConnectionIdentifier.jndiName = "esme"
+
+ if (!DB.jndiJdbcConnAvailable_?) DB.defineConnectionManager(DefaultConnectionIdentifier, DBVendor)
+ // where to search snippet
+ LiftRules.addToPackages("us.esme")
+
+ if (Props.mode == Props.RunModes.Test) {
+ Schemifier.destroyTables_!!(Log.infoF _, User, ExtSession,
+ Message, Mailbox, Tag,
+ Group, Relationship, MessageTag,
+ AuthToken, UrlStore, Tracking,
+ Action, DidPerform)
+ }
+
+ Schemifier.schemify(true, Log.infoF _, User, ExtSession, Message,
+ Mailbox, Tag,
+ Group, Relationship, MessageTag, AuthToken,
+ UrlStore, Tracking, Action, DidPerform)
+
+ LiftRules.prependTemplate(User.templates)
+
+ LiftRules.appendStatelessDispatch {
+ case r @ Req("api" :: "send_msg" :: Nil, "", PostRequest)
+ if r.param("token").isDefined =>
+ () => RestAPI.sendMsgWithToken(r)
+ }
+
+ LiftRules.appendDispatch(ESMEOpenIDVendor.dispatchPF)
+
+ LiftRules.siteMapFailRedirectLocation = List("static", "about")
+
+ LiftRules.prependRewrite {
+ case RewriteRequest(ParsePath("user" :: user :: Nil,"", _,_), _, _) =>
+ RewriteResponse( List("user_view", "index"), Map("uid" -> user))
+ case RewriteRequest(ParsePath("tag" :: tag :: Nil,"", _,_), _, _) =>
+ RewriteResponse( List("user_view", "tag"), Map("tag" -> tag))
+
+ case RewriteRequest(ParsePath("conversation" :: cid :: Nil, "", _, _),
+ _, _) =>
+ RewriteResponse(List("user_view", "conversation"), Map("cid" -> cid))
+
+ case RewriteRequest(ParsePath("search" :: term :: Nil,"", _,_), _, _) =>
+ RewriteResponse( List("user_view", "search"), Map("term" -> term))
+ }
+
+ LiftRules.appendDispatch(UrlStore.redirectizer)
+
+
+ LiftRules.siteMapFailRedirectLocation = List("static", "about")
+
+ // Build SiteMap
+ val entries = Menu(Loc("Home", List("index"), "Home")) ::
+ Menu(Loc("list_users", List("user_view", "all"), "List Users")) ::
+ Menu(Loc("user", List("user_view", "index"), "User Info", Hidden)) ::
+ Menu(Loc("conv", List("user_view", "conversation"), "Conversation", Hidden)) ::
+ Menu(Loc("about", List("static", "about"), "About", Hidden)) ::
+ Menu(Loc("tag", List("user_view", "tag"), "Tag", Hidden)) ::
+ Menu(Loc("search", List("user_view", "search"), "Search", Hidden)) ::
+ User.sitemap :::
+ Track.menuItems :::
+ Auth.menuItems :::
+ ActionView.menuItems
+
+ LiftRules.setSiteMap(SiteMap(entries:_*))
+ S.addAround(User.requestLoans)
+ S.addAround(ExtSession.requestLoans)
+
+ LiftRules.appendViewDispatch {
+ case "user_view" :: _ => UserView
+ }
+
+ LiftRules.prependDispatch(RestAPI.dispatch)
+
+ LiftRules.appendEarly(makeUtf8)
+
+ Distributor.touch
+
+ DB.addLogFunc(S.logQuery _)
+ S.addAnalyzer(RequestAnalyzer.analyze _)
+ }
+ private def makeUtf8(req: HttpServletRequest): Unit = {req.setCharacterEncoding("UTF-8")}
+}
+
+object Compass {
+ // Set up Compass for search
+ val conf = new CompassConfiguration().configure("/props/compass.cfg.xml").addClass((new Message).clazz)
+ val compass = conf.buildCompass()
+ if (!compass.getSearchEngineIndexManager.indexExists)
+ {
+ // Create Index if one does not exist
+ compass.getSearchEngineIndexManager().createIndex()
+ }
+}
+
+
+object RequestAnalyzer {
+
+ def analyze(req: Can[Req], time: Long, queries: List[(String, Long)]): Unit = {
+ val longQueries = (queries.filter(_._2 > 30))
+ if (time > 50 || longQueries.?) {
+ Log.info("Request "+req.map(_.uri).openOr("No Request")+
+ " took "+time+" query "+longQueries.comma)
+ }
+ }
+}
+
+object DBVendor extends ConnectionManager {
+ private var pool: List[Connection] = Nil
+ private var poolSize = 0
+ private val maxPoolSize = 4
+
+ private def createOne: Can[Connection] = try {
+ if (Props.getBool("use_prod_psql", false)) {
+ Class.forName("org.postgresql.Driver")
+ val dm = DriverManager.
+ getConnection("jdbc:postgresql://localhost/esme_prod",
+ Props.get("db_user", "dpp"),
+ Props.get("db_pwd", ""))
+ Full(dm)
+ } else if (Props.getBool("use_local_psql", false)) {
+ Class.forName("org.postgresql.Driver")
+ val dm = DriverManager.
+ getConnection("jdbc:postgresql://localhost/esme_dev",
+ Props.get("db_user", "dpp"),
+ Props.get("db_pwd", ""))
+ Full(dm)
+ } else {
+ Class.forName("org.apache.derby.jdbc.EmbeddedDriver")
+ val driverName = Props.mode match {
+ case Props.RunModes.Test => "jdbc:derby:esme_test_db;create=true"
+ case _ => "jdbc:derby:esme_db;create=true"
+ }
+
+ val dm = DriverManager.getConnection(driverName)
+ Full(dm)
+ }
+ } catch {
+ case e : Exception => e.printStackTrace; Empty
+ }
+
+ def newConnection(name: ConnectionIdentifier): Can[Connection] = synchronized {
+ pool match {
+ case Nil if poolSize < maxPoolSize => val ret = createOne
+ poolSize = poolSize + 1
+ ret.foreach(c => pool = c :: pool)
+ ret
+
+ case Nil => wait(1000L); newConnection(name)
+ case x :: xs => try {
+ x.setAutoCommit(false)
+ Full(x)
+ } catch {
+ case e => try {
+ pool = xs
+ poolSize = poolSize - 1
+ x.close
+ newConnection(name)
+ } catch {
+ case e => newConnection(name)
+ }
+ }
+ }
+ }
+
+ def releaseConnection(conn: Connection): Unit = synchronized {
+ pool = conn :: pool
+ notify
+ }
+}
+
Added: incubator/esme/trunk/server/src/main/scala/us/esme/actor/Distributor.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/actor/Distributor.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/actor/Distributor.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/actor/Distributor.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+/*
+ * Distributor.scala
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package us.esme.actor
+
+import scala.actors.Actor
+import Actor._
+
+import net.liftweb._
+import http._
+import util._
+
+import us.esme._
+import model._
+
+import scala.xml.{Elem}
+
+object Distributor extends Actor {
+ def act = loop {
+ react {
+ case StartMeUp =>
+ link(ActorWatcher)
+ User.findAll.map(_.id.is).foreach(findOrCreateUser)
+ Group.findAll.map(_.id.is).foreach(findOrCreateGroup)
+
+ case UserCreatedMessage(user, text, tags, when,
+ metaData,
+ source,
+ inReplyTo) =>
+ findOrCreateUser(user) !
+ UserActor.CreateMessage(text, tags,
+ when, metaData, source, inReplyTo)
+
+ case AddMessageToMailbox(user, message, reason) =>
+ findOrCreateUser(user) ! UserActor.AddToMailbox(message, reason)
+
+ case Listen(user, who) =>
+ findOrCreateUser(user) ! UserActor.Listen(who)
+
+ case Unlisten(user, who) =>
+ findOrCreateUser(user) ! UserActor.Unlisten(who)
+
+ case LatestMessages(user, cnt) =>
+ findOrCreateUser(user).forward(UserActor.LatestMessages(cnt))
+
+ case m @ UserUpdated(id) =>
+ users.get(id).foreach(_ ! m)
+
+ case nm @ NewMessage(msg) =>
+ val toSend = UserActor.TestForTracking(msg)
+ users.values.foreach(_ ! toSend)
+ listeners.foreach(_ ! nm)
+
+ case UpdateTrackingFor(userId, ttype) =>
+ for (user <- users.get(userId))
+ user ! UserActor.UpdateTracking(ttype)
+
+ case PublicTimelineListeners(who) =>
+ listeners = who :: listeners
+
+ case PublicTimelineUnlisteners(who) =>
+ listeners = listeners.filter(_ ne who)
+
+ case _ =>
+ }
+ }
+
+ private case object StartMeUp
+
+ case class UserCreatedMessage(user: Long, text: String, tags: List[String],
+ when: Long,
+ metaData: Can[Elem],
+ source: String,
+ replyTo: Can[Long])
+ case class AddMessageToMailbox(user: Long, message: Message, reason: MailboxReason)
+ case class Listen(user: Long, who: Actor)
+ case class Unlisten(user: Long, who: Actor)
+ case class LatestMessages(user: Long, cnt: Int)
+ case class NewMessage(msg: Message)
+ case class UpdateTrackingFor(user: Long, which: TrackingType)
+ case class UserUpdated(userId: Long)
+ case class PublicTimelineListeners(who: Actor)
+ case class PublicTimelineUnlisteners(who: Actor)
+ sealed trait TrackingType
+ case object PerformTrackingType extends TrackingType
+ case object TrackTrackingType extends TrackingType
+
+ start
+ this ! StartMeUp
+
+ // do nothing
+ def touch {
+
+ }
+
+ private var users: Map[Long, UserActor] = Map.empty
+ private var groups: Map[Long, GroupActor] = Map.empty
+ private var listeners: List[Actor] = Nil
+
+ private def findOrCreateUser(user: Long): UserActor = {
+ users.get(user) match {
+ case Some(ret) => ret
+ case _ =>
+ val ret = new UserActor
+ ret.start
+ ret ! UserActor.StartMeUp(user)
+ users = users + (user -> ret)
+ ret
+ }
+ }
+
+ private def findOrCreateGroup(group: Long) {
+ groups.get(group) match {
+ case Some(ret) => ret
+ case _ =>
+ val ret = new GroupActor
+ ret.start
+ ret ! GroupActor.StartMeUp(group)
+ groups = groups + (group -> ret)
+ ret
+ }
+ }
+}
Added: incubator/esme/trunk/server/src/main/scala/us/esme/actor/GroupActor.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/actor/GroupActor.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/actor/GroupActor.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/actor/GroupActor.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+package us.esme.actor
+
+import scala.actors.Actor
+import Actor._
+
+
+import net.liftweb._
+import http._
+
+import us.esme._
+import model._
+
+object GroupActor {
+ case class StartMeUp(group: Long)
+}
+
+class GroupActor extends Actor {
+ import GroupActor._
+
+ def act = loop {
+ react {
+ case StartMeUp =>
+ link(ActorWatcher)
+ }
+ }
+}
Added: incubator/esme/trunk/server/src/main/scala/us/esme/actor/HttpSender.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/actor/HttpSender.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/actor/HttpSender.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/actor/HttpSender.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+
+
+package us.esme.actor
+
+import scala.actors.Actor
+import Actor._
+
+import net.liftweb._
+import http._
+import util._
+import net.liftweb.http.testing._
+
+import us.esme._
+import model._
+import lib._
+
+import org.apache.commons.httpclient._
+
+object HttpSender extends Actor with GetPoster {
+ def act = loop {
+ react {
+ case StartMeUp =>
+ link(ActorWatcher)
+
+
+ case SendAMessage(action, msg, token) =>
+ send(action, msg, token)
+
+ case _ =>
+ }
+ }
+
+ private case object StartMeUp
+ case class SendAMessage(action: Performances, msg: Message, token: String)
+
+ private def send(action: Performances, msg: Message, token: String) {
+ import Mailer._
+
+ action match {
+ case MailTo(who) => Mailer.sendMail(From("i@esme.us"), Subject("msg"),
+ To(who),
+ XHTMLMailBodyType(msg.digestedXHTML))
+ case HttpTo(url, headers) =>
+ post(url, httpClient,
+ ("X-ESME-Token" -> token) :: headers,
+ msg.toXml)
+
+ case PerformResend | PerformFilter => // IGNORE
+
+ }
+ }
+
+ def httpClient = {
+ val ret = new HttpClient(new SimpleHttpConnectionManager(false))
+
+ for (host <- Props.get("http.proxyHost"))
+ ret.getHostConfiguration.setProxy(host,
+ Props.getInt("http.proxyPort",80))
+ ret
+ }
+
+ start
+ this ! StartMeUp
+
+ def baseUrl = ""
+}
Added: incubator/esme/trunk/server/src/main/scala/us/esme/actor/MessagePullActor.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/actor/MessagePullActor.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/actor/MessagePullActor.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/actor/MessagePullActor.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,55 @@
+package us.esme.actor
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+import scala.actors.Actor
+import scala.actors.TIMEOUT
+import scala.actors.Actor._
+import us.esme.actor.Distributor.{UserCreatedMessage=>Msg}
+
+class MessagePullActor(val messageProcessor: Actor, val refreshSeconds: Int, private var lastMessage: Option[Msg], val messageSource: UniqueMessageSource) extends Actor {
+
+ def act {
+ loop {
+ reactWithin (refreshSeconds * 1000) {
+ case (msgs: List[Msg]) => {
+ val lastMessages = messageSource.getLastSortedMessages(msgs, lastMessage)
+ for (message <- lastMessages) {
+ messageProcessor ! message
+ lastMessage = Some(message)
+ }
+ }
+ case TIMEOUT => actor {
+ // "this" used to reference invoking actor
+ this ! messageSource()
+ }
+ }
+ }
+ }
+
+}
+
+trait UniqueMessageSource extends (() => List[Msg]) {
+ def messageSorter(a: Msg, b: Msg) = a.when < b.when
+
+ def getLastSortedMessages(msgs: List[Msg], lastMessage: Option[Msg]): List[Msg] = {
+ lastMessage match {
+ case Some(message: Msg) => msgs.filter{messageSorter(message, _)}
+ case None => msgs
+ }
+ }.sort(messageSorter)
+}
Added: incubator/esme/trunk/server/src/main/scala/us/esme/actor/UserActor.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/actor/UserActor.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/actor/UserActor.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/actor/UserActor.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+package us.esme.actor
+
+import scala.actors.Actor
+import Actor._
+
+import net.liftweb._
+import http._
+import util._
+import mapper._
+
+import us.esme._
+import model._
+import lib._
+
+import java.util.logging._
+import java.util.{TimeZone, Calendar}
+import scala.xml.{Elem}
+
+object UserActor {
+ private[actor] case class StartMeUp(user: Long)
+ private[actor] case class CreateMessage(text: String, tags: List[String],
+ when: Long, metaData: Can[Elem],
+ source: String,
+ replyTo: Can[Long])
+ private[actor] case class AddToMailbox(msg: Message, reason: MailboxReason)
+ private[actor] case class Listen(who: Actor)
+ private[actor] case class Unlisten(who: Actor)
+ private[actor] case class LatestMessages(cnt: Int)
+ private[actor] case class TestForTracking(msg: Message)
+ private[actor] case class UpdateTracking(ttype: Distributor.TrackingType)
+
+ case class MessageReceived(msg: Message, reason: MailboxReason)
+
+ val logger: Logger = Logger.getLogger("us.esme.actor")
+}
+
+class UserActor extends Actor {
+ import UserActor._
+
+ private var userId: Long = 0
+
+ private var userTimezone: TimeZone = _
+
+ private var listeners: List[Actor] = Nil
+
+ private var tracking: List[TrackingMatcher] = Nil
+
+ private var perform: List[PerformMatcher] = Nil
+
+ private var _mailbox: Array[Long] = Array()
+
+ private def followers: List[Long] = User.followerIdsForUserId(userId)
+
+ private case class RunFunc(f: () => Unit)
+
+ def act = loop {
+ react {
+ case m @ Distributor.UserUpdated(_) =>
+ User.find(userId).
+ foreach(u => userTimezone = TimeZone.getTimeZone(u.timezone))
+ listeners.foreach(_ ! m)
+
+ case StartMeUp(user) =>
+ link(ActorWatcher)
+ userId = user
+ User.find(userId).
+ foreach(u => userTimezone = TimeZone.getTimeZone(u.timezone))
+
+ _mailbox = Mailbox.mostRecentMessagesFor(userId, 500).
+ map(_._1.id.is).toArray
+
+ this ! UpdateTracking(Distributor.TrackTrackingType)
+ this ! UpdateTracking(Distributor.PerformTrackingType)
+
+ case RunFunc(f) => f()
+
+ case CreateMessage(text, tags, when, metaData, source, replyTo) =>
+ val tagLst = tags.removeDuplicates.map(Tag.findOrCreate)
+
+ Message.create.author(userId).when(when).
+ source(source).
+ setTextAndTags(text, tagLst, metaData).map{msg =>
+ // do some security... only reply to messages
+ // that are in our mailbox
+ for (rt <- replyTo;
+ mb <- Mailbox.find(By(Mailbox.message, rt),
+ By(Mailbox.user, userId))) msg.replyTo(rt)
+
+ msg.saveMe
+
+ Distributor ! Distributor.AddMessageToMailbox(userId, msg, NoReason)
+
+ for (id <- followers)
+ Distributor ! Distributor.AddMessageToMailbox(id, msg, NoReason)
+
+ for (id <- msg.sentToIds)
+ Distributor ! Distributor.AddMessageToMailbox(id, msg,
+ DirectReason(userId))
+
+ for (convId <- msg.conversation.can ;
+ val msgId = Message.findMap(By(Message.conversation, convId))
+ (m => Full(m.id.is));
+ userId <- (Mailbox.findMap(InRaw(Mailbox.message, msgId.mkString(", "),
+ IHaveValidatedThisSQL("dpp", "Aug 27. 2008")))
+ (mb => Full(mb.user.is))).removeDuplicates)
+ Distributor ! Distributor.AddMessageToMailbox(userId, msg, ConversationReason(convId))
+
+ Distributor ! Distributor.NewMessage(msg)
+ }
+
+ case AddToMailbox(msg, reason) =>
+ addToMailbox(msg, reason)
+
+
+ case TestForTracking(msg) =>
+ for (t <- tracking.find(_.doesMatch_?(msg)))
+ this ! AddToMailbox(msg, TrackReason(t.trackId))
+
+
+ case UpdateTracking(ttype) =>
+ ttype match {
+ case Distributor.TrackTrackingType =>
+ tracking = Tracking.findAll(By(Tracking.user, userId),
+ By(Tracking.disabled, false),
+ By(Tracking.removed, false)).
+ flatMap(_.matcher)
+
+ case Distributor.PerformTrackingType =>
+ perform = Action.findAll(By(Action.user, userId),
+ By(Action.disabled, false),
+ By(Action.removed, false)).
+ map(_.matcher)
+ }
+
+ case Listen(who) => listeners = who :: listeners
+
+ case Unlisten(who) => listeners = listeners.filter(_ ne who)
+
+ case LatestMessages(cnt) => reply(_mailbox.take(cnt).toList)
+ }
+ }
+
+ def buildCalendar = userTimezone match {
+ case null => Calendar.getInstance()
+ case tz => Calendar.getInstance(tz)
+ }
+
+ private def addToMailbox(msg: Message, reason: MailboxReason) {
+ // if the message is not in my mailbox
+ if (Mailbox.find(By(Mailbox.message, msg),
+ By(Mailbox.user, userId)).isEmpty) {
+
+ // get all the performance things
+ val cal = buildCalendar
+ val toDo = perform.filter(_.func(msg, userId, cal))
+
+ // is one of those reasons rejection of the message
+ val reject = toDo.exists(_.filter_?)
+
+ // if we're not rejecting the message
+ if (!reject) {
+ val mb = Mailbox.create.user(userId).message(msg)
+ reason match {
+ case TrackReason(trackId) => mb.viaTrack(trackId)
+ case DirectReason(fromId) => mb.directlyFrom(fromId)
+ case ConversationReason(convId) => mb.conversation(convId)
+ case ResendReason(resender) => mb.resentBy(resender)
+ case NoReason =>
+ }
+ mb.saveMe
+
+ _mailbox = (msg.id.is :: _mailbox.toList).take(500).toArray
+
+ listeners.foreach(_ ! MessageReceived(msg, reason))
+
+ toDo.foreach {
+ td =>
+
+ td.whatToDo match {
+ case m @ MailTo(_) =>
+ HttpSender ! HttpSender.SendAMessage(m, msg, td.uniqueId)
+
+ case h @ HttpTo(_, _) =>
+ HttpSender ! HttpSender.SendAMessage(h, msg, td.uniqueId)
+
+ case PerformResend =>
+ for (id <- followers)
+ Distributor !
+ Distributor.AddMessageToMailbox(id, msg, ResendReason(userId))
+
+ case PerformFilter => // IGNORE
+ }
+ }
+ }
+ }
+ }
+}
Added: incubator/esme/trunk/server/src/main/scala/us/esme/api/RestAPI.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/api/RestAPI.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/api/RestAPI.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/api/RestAPI.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+/*
+ * RestAPI.scala
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package us.esme.api
+
+import net.liftweb._
+import http._
+import rest._
+import util._
+import mapper._
+import Helpers._
+
+import us.esme._
+import model._
+import actor._
+
+import scala.xml.{NodeSeq, Text, Elem, XML}
+import scala.actors.Actor
+import Actor._
+
+import scala.collection.mutable.ListBuffer
+import java.util.logging._
+
+object RestAPI extends XMLApiHelper {
+ val logger: Logger = Logger.getLogger("us.esme.api")
+
+ def dispatch: LiftRules.DispatchPF = {
+ case Req("api" :: "status" :: Nil, "", GetRequest) => status
+ case Req("api" :: "login" :: Nil, "", PostRequest) => login
+ case Req("api" :: "logout" :: Nil, "", GetRequest) => logout
+ case Req("api" :: "get_msgs" :: Nil, "", GetRequest) => getMsgs
+ case Req("api" :: "wait_for_msgs" :: Nil, "", GetRequest) =>
+ waitForMsgs
+
+ case Req("api" :: "send_msg" :: Nil, "", PostRequest) =>
+ () => sendMsg(User.currentUser.map(_.id.is), S)
+
+ case Req("api" :: "get_following" :: Nil, _, GetRequest) =>
+ following(calcUser)
+ case Req("api" :: "get_followers" :: Nil, _, GetRequest) =>
+ followers(calcUser)
+ case Req("api" :: "follow" :: Nil, _, PostRequest) =>
+ performFollow(S.param("user"))
+ case Req("api" :: "unfollow" :: Nil, _, PostRequest) =>
+ performUnfollow(S.param("user"))
+ case Req("api" :: "all_users" ::
+ Nil, _, GetRequest) => allUsers _
+ case Req("api" :: "get_tagcloud" :: Nil, "", GetRequest) =>
+ () => getTagCloud(S)
+
+ // DPP to document
+ case Req("api" :: "get_tracking" :: Nil, "", GetRequest) =>
+ getTracking
+
+ case Req("api" :: "add_tracking" :: Nil, "", PostRequest) =>
+ addTracking
+
+ case Req("api" :: "remove_tracking" :: Nil, "", PostRequest) =>
+ removeTracking
+
+ case Req("api" :: "get_conversation" :: Nil, "", GetRequest) =>
+ getConversation
+
+ case Req("api" :: "get_actions" :: Nil, "", GetRequest) =>
+ getActions _
+
+ case Req("api" :: "add_action" :: Nil, "", PostRequest) =>
+ addAction _
+
+ case Req("api" :: "enable_action" :: Nil, "", PostRequest) =>
+ enableAction _
+
+ case Req("api" :: "delete_action" :: Nil, "", PostRequest) =>
+ deleteAction _
+ }
+
+ def findAction: Can[Action] =
+ for (user <- User.currentUser ?~ "Not Logged In";
+ id <- S.param("actionid") ?~ "id param not supplied";
+ action <- Action.find(By(Action.user, user),
+ By(Action.id, id.toLong),
+ By(Action.removed, false))) yield action
+
+ def addAction(): LiftResponse = {
+ val ret: Can[NodeSeq] =
+ for (user <- User.currentUser ?~ "Not logged in";
+ name <- S.param("name") ?~ "'name' param not supplied";
+ test <- S.param("test") ?~ "'test' param not supplied";
+ action <- S.param("action") ?~ "'action' param not supplied";
+ val a = Action.create.user(user).name(name);
+ a2 <- a.setTest(test);
+ a3 <- a.setAction(action)) yield a3.saveMe.toXml
+
+ ret
+ }
+
+ def getActions(): LiftResponse = {
+ val ret: Can[NodeSeq] =
+ for (user <- User.currentUser ?~ "Not logged in")
+ yield user.performing.flatMap(_.toXml)
+
+ ret
+ }
+
+ def enableAction(): LiftResponse = {
+ val ret: Can[Boolean] =
+ for (action <- findAction;
+ enabled <- S.param("enabled").map(toBoolean) ?~ "enabled param not supplied")
+ yield action.disabled(!enabled).save
+
+ ret
+ }
+
+ def deleteAction(): LiftResponse = {
+ val ret: Can[Boolean] =
+ for (action <- findAction)
+ yield action.removed(true).save
+
+ ret
+ }
+
+ private def calcUser: Can[User] =
+ S.param("user").flatMap(User.findFromWeb) or
+ User.currentUser
+
+ def getTracking(): LiftResponse = {
+ val ret: Can[NodeSeq] =
+ for (user <- User.currentUser ?~ "Not logged in")
+ yield Tracking.findAll(By(Tracking.user, user)).flatMap(_.toXml)
+ ret
+ }
+
+ def getConversation(): LiftResponse = {
+ val ret: Can[NodeSeq] =
+ for (user <- User.currentUser ?~ "Not logged in";
+ id <- S.param("conversationid").map(toLong) ?~ "id param missing"
+ ) yield <conversation id={id.toString}>{
+ Message.findAndPrime(By(Message.conversation, id),
+ OrderBy(Message.id, Ascending)).map(_.toXml)
+ }</conversation>
+
+ ret
+ }
+
+ def removeTracking(): LiftResponse = {
+ val ret: Can[Boolean] =
+ for (user <- User.currentUser ?~ "Not logged in";
+ id <- S.param("trackid") ?~ "id param missing";
+ track <- Tracking.find(By(Tracking.id, id.toLong),
+ By(Tracking.user, user)) ?~ "Couldn't find tracking item"
+ ) yield track.removed(true).save
+
+ ret
+ }
+
+ def addTracking(): LiftResponse = {
+ val ret: Can[Boolean] =
+ for (user <- User.currentUser ?~ "Not logged in";
+ toTrack <- (S.param("track") ?~ "No track param") if toTrack.trim.length > 0)
+ yield
+ Tracking.create.user(user).regex(toTrack).save
+
+ ret
+ }
+
+ def status(): LiftResponse =
+ {
+ val ret: Can[NodeSeq] = User.currentUser.map(_.toXml)
+ ret
+ }
+
+ def allUsers(): LiftResponse =
+ for (user <- User.findAll) yield user.toXml
+
+
+ def following(muser: Can[User])(): LiftResponse = {
+ val r: Can[NodeSeq] = for (user <- muser) yield
+ user.following().map(_.toXml)
+
+ r
+ }
+
+ def followers(muser: Can[User])(): LiftResponse = {
+ val r: Can[NodeSeq] = for (user <- muser) yield
+ user.followers().map(_.toXml)
+
+ r
+ }
+
+ def performFollow(userName: Can[String])(): LiftResponse = {
+ val r: Can[Boolean] =
+ for (user <- User.currentUser;
+ userName <- userName;
+ other <- User.findFromWeb(userName)
+ ) yield user.follow(other)
+
+ r
+ }
+
+ def performUnfollow(userName: Can[String])(): LiftResponse = {
+ val r: Can[Boolean] =
+ for (user <- User.currentUser;
+ userName <- userName;
+ other <- User.findFromWeb(userName)
+ ) yield user.unfollow(other)
+
+ r
+ }
+
+ def login(): LiftResponse = {
+ val res: Can[Boolean] = if (User.loggedIn_?) Empty else
+ for (token <- S.param("token") ?~ "No 'token' param";
+ auth <- AuthToken.find(By(AuthToken.uniqueId, token))
+ ?~ "Token not found";
+ user <- auth.user.obj;
+ session <- S.session
+ ) yield {
+ User.logUserIn(user)
+ val myActor = buildActor(user.id)
+ restActor(Full(myActor))
+ true
+ }
+
+ res
+ }
+
+ def logout(): LiftResponse = {
+ User.logUserOut()
+ true
+ }
+
+ def waitForMsgs(): LiftResponse = {
+ val seq: Long = CometActor.next
+
+ def waitForAnswer: Can[List[(Message, MailboxReason)]] =
+ receiveWithin(6L * 60L * 1000L) {
+ case (s2, ret: List[(Message, MailboxReason)]) if s2 == seq =>
+ Full(ret)
+ case (s2, _, _) if s2 != seq => waitForAnswer
+ case _ => Empty
+ }
+
+ var r: Can[NodeSeq] =
+ for (act <- restActor.is ?~ "No REST actor";
+ val ignore = act ! ListenFor(self, 5 minutes, seq);
+ answer <- waitForAnswer ?~ "Didn't get an answer")
+ yield answer.flatMap{ case (msg, reason) => msg.toXml % reason.attr}
+
+ r
+ }
+
+ def sendMsgWithToken(req: Req): Can[LiftResponse] = {
+ for (token <- req.param("token");
+ auth <- AuthToken.find(By(AuthToken.uniqueId, token));
+ userId <- auth.user.can;
+ ret <- sendMsg(Full(userId), req)) yield ret
+ }
+
+ def sendMsg(theUser: Can[Long], params: HasParams): LiftResponse = {
+ val r: Can[Boolean] =
+ for (user <- theUser ?~ "User not found";
+ msg <- params.param("message") ?~ "Message not included")
+ yield {
+ val from: String = params.param("via") openOr "api"
+
+ val xml: Can[Elem] = params.param("metadata").flatMap(md =>
+ tryo(XML.loadString(md)))
+
+ Distributor !
+ Distributor.UserCreatedMessage(user, msg,
+ Tag.split(params.param("tags")
+ openOr ""),
+ millis,
+ xml,
+ from,
+ params.param("replyto").map(toLong))
+ true
+ }
+ r
+ }
+
+ def getMsgs(): LiftResponse = {
+ val t: Can[NodeSeq] =
+ for (tagName <- S.param("tag");
+ tag <- Tag.find(By(Tag.name, tagName)))
+ yield tag.findMessages.map(_.toXml)
+
+ val r: Can[NodeSeq] =
+ t or (for (user <- calcUser ?~ "User not found";
+ val lst = Mailbox.mostRecentMessagesFor(user.id, 40))
+ yield lst.flatMap{ case (msg, why) => msg.toXml % why.attr})
+
+ r
+ }
+
+ def getTagCloud(params: HasParams): LiftResponse = {
+ // By default, get the normalised word frequencies from the messages
+ val numTags = (params.param("numTags") openOr "20").toInt
+ val numMsgs = 40 //(params.param("numMsgs") openOr "40").toInt
+
+ val r: Can[NodeSeq] =
+ for (user <- calcUser ?~ "User not found";
+ val lst = Mailbox.mostRecentMessagesFor(user.id, numMsgs).map(_._1))
+ yield
+ <tag_cloud>
+ {
+ for (t <- Tag.centreWeightedTopNTagFreqs(lst, numTags)) yield <tag name={t._1} weight={t._2.toString} />
+ }
+ {
+ for (t <- Message.centreWeightedTopNWordFreqs(lst, numTags)) yield <word name={t._1} weight={t._2.toString} />
+ }
+ </tag_cloud>
+
+
+ r
+ }
+
+ def createTag(in: NodeSeq) = <esme_api>{in}</esme_api>
+
+
+ private def buildActor(userId: Long): RestActor = {
+ val ret = new RestActor
+ ret.start
+ ret ! StartUp(userId)
+ ret
+ }
+
+ object restActor extends SessionVar[Can[RestActor]](Empty) {
+ override def cleanupFunc: Can[() => Unit] = Full(() => this.is.map(_ ! ByeBye))
+ }
+
+
+ class RestActor extends Actor {
+ private var userId: Long = _
+ private var msgs: List[(Message, MailboxReason)] = Nil
+ private var listener: Can[(Actor, Long)] = Empty
+
+ def act = loop {
+ react {
+ case StartUp(userId) =>
+ link(ActorWatcher)
+ this.userId = userId
+ Distributor ! Distributor.Listen(userId, this)
+
+ case ByeBye =>
+ unlink(ActorWatcher)
+ Distributor ! Distributor.Unlisten(userId, this)
+ self.exit()
+
+ case UserActor.MessageReceived(msg, reason) =>
+ msgs = (msg, reason) :: msgs
+ listener.foreach {
+ who =>
+ who._1 ! (who._2, msgs)
+ listener = Empty
+ msgs = Nil
+ }
+
+ case ReleaseListener =>
+ listener.foreach(l => l._1 ! (l._2, Nil))
+ listener = Empty
+
+ case ListenFor(who, len, seq) =>
+ msgs match {
+ case Nil =>
+ listener.foreach(l => l._1 ! (l._2, Nil))
+ listener = Full((who, seq))
+ ActorPing.schedule(this, ReleaseListener, len)
+
+ case xs =>
+ who ! (seq, xs)
+ msgs = Nil
+ listener = Empty
+ }
+ }
+ }
+ }
+
+ private case class StartUp(userId: Long)
+ private case object ByeBye
+ private case class ListenFor(who: Actor, howLong: TimeSpan, seq: Long)
+ private case object ReleaseListener
+}
Added: incubator/esme/trunk/server/src/main/scala/us/esme/comet/.keep
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/comet/.keep?rev=726084&view=auto
==============================================================================
(empty)
Added: incubator/esme/trunk/server/src/main/scala/us/esme/comet/PublicTimeline.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/comet/PublicTimeline.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/comet/PublicTimeline.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/comet/PublicTimeline.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,87 @@
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+package us.esme.comet
+
+import net.liftweb.http._
+import net.liftweb.mapper._
+import net.liftweb.util._
+import net.liftweb.util.Helpers._
+import scala.xml._
+import js._
+import JsCmds._
+import JE._
+
+import us.esme._
+import actor._
+import model._
+import lib._
+
+import java.text._
+
+class PublicTimeline extends CometActor with MsgFormat {
+
+ def defaultPrefix = "timeline"
+
+ private var messages: List[Long] = Nil
+ private var lastRender = millis
+ private var scheduled = false
+
+ override def localSetup() {
+ super.localSetup()
+ Distributor ! Distributor.PublicTimelineListeners(this)
+ messages = Message.findAll(OrderBy(Message.id, Descending),
+ MaxRows(40)).map(_.id.is)
+ }
+
+ override def localShutdown() {
+ super.localShutdown()
+ Distributor ! Distributor.PublicTimelineUnlisteners(this)
+ }
+
+ def render = {
+ lastRender = millis
+ scheduled = false
+ val msgMap = Message.findMessages(messages)
+ val toDisplay = messages.flatMap(msgMap.get)
+
+ <xml:group>
+ {
+ toDisplay.map(m => formatMsg(m, true, true))
+ }
+ </xml:group>
+ }
+
+ override implicit def xmlToXmlOrJsCmd(in: NodeSeq): RenderOut = new RenderOut(Full(in), fixedRender, Empty, Empty, false)
+
+ override def lowPriority = {
+ case ForceRender =>
+ reRender(false)
+
+ case Distributor.NewMessage(msg) =>
+ messages = (msg.id.is :: messages).take(40)
+
+ if ((millis - lastRender) < 30000L) {
+ if (!scheduled) {
+ scheduled = true
+ ActorPing.schedule(this, ForceRender, 30000L)
+ }
+ }
+ else reRender(false)
+ }
+}
+
+case object ForceRender
Added: incubator/esme/trunk/server/src/main/scala/us/esme/comet/TagCloud.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/comet/TagCloud.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/comet/TagCloud.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/comet/TagCloud.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,95 @@
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+package us.esme.comet
+
+import net.liftweb.http._
+import net.liftweb.util._
+import net.liftweb.util.Helpers._
+import scala.xml._
+import js._
+import JsCmds._
+import JE._
+
+import us.esme._
+import actor._
+import model._
+import lib._
+
+import java.text._
+
+class TagCloud extends CometActor with MsgFormat {
+
+ def defaultPrefix = "tagcloud"
+
+ private var messages: List[Long] = Nil
+
+ override def localSetup() {
+ super.localSetup()
+ for (user <- User.currentUser) {
+ Distributor ! Distributor.Listen(user.id, this)
+ Distributor !? (2000, Distributor.LatestMessages(user.id, 40)) match {
+ case Some(msg: List[Long]) => messages = msg
+ case x =>
+ }
+ }
+ }
+
+ override def localShutdown() {
+ super.localShutdown()
+ for (user <- User.currentUser) {
+ Distributor ! Distributor.Unlisten(user.id, this)
+ }
+ }
+
+ private def lookupMessages(): List[Message] = {
+ val mm = Message.findMessages(messages)
+ messages.flatMap(mm.get)
+ }
+
+ def render = {
+ val messages = lookupMessages()
+ //Sort the tags & words to put the most prominent in the middle
+ <div id="tagcloud">
+ <p id="tag-para">Tags</p>
+ <p>
+ {
+ for ((name, weight) <- Tag.centreWeightedTopNTagFreqs(messages, 20))
+ yield <xml:group><a href={"/tag/" + name}
+ style={"font-size: "+(0.5F + weight)+"em; text-decoration: none;"}>{
+ name}</a> </xml:group>
+ }
+ </p>
+ <p/>
+ <p id="word-para">Words</p>
+ <p>
+ {
+ for ((name, weight) <- Message.centreWeightedTopNWordFreqs(messages, 20))
+ yield <xml:group><a href={"/search/" + name}
+ style={"font-size: "+(0.5F + weight)+"em; text-decoration: none;"}>{
+ name}</a> </xml:group>
+ }
+ </p>
+ </div>
+ }
+
+
+ override def lowPriority = {
+ case UserActor.MessageReceived(msg, _) =>
+ messages = (msg.id.is :: messages).take(40)
+ reRender(false)
+ }
+}
Added: incubator/esme/trunk/server/src/main/scala/us/esme/comet/Timeline.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/comet/Timeline.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/comet/Timeline.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/comet/Timeline.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,79 @@
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+package us.esme.comet
+
+import net.liftweb.http._
+import net.liftweb.util._
+import net.liftweb.util.Helpers._
+import scala.xml._
+import js._
+import JsCmds._
+import JE._
+
+import us.esme._
+import actor._
+import model._
+import lib._
+
+import java.text._
+
+class Timeline extends CometActor with MsgFormat {
+
+ def defaultPrefix = "timeline"
+
+ private var messages: List[Long] = Nil
+
+ override def localSetup() {
+ super.localSetup()
+ for (user <- User.currentUser) {
+ Distributor ! Distributor.Listen(user.id, this)
+ Distributor !? (200, Distributor.LatestMessages(user.id, 40)) match {
+ case Some(msg: List[Long]) => messages = msg
+ case x =>
+ }
+ }
+ }
+
+ override def localShutdown() {
+ super.localShutdown()
+ for (user <- User.currentUser) {
+ Distributor ! Distributor.Unlisten(user.id, this)
+ }
+ }
+
+ def render = {
+ val msgMap = Message.findMessages(messages)
+ val toDisplay = messages.flatMap(msgMap.get)
+
+ <xml:group>
+ {
+ toDisplay.map(m => <xml:group>{formatMsg(m, true, true)}</xml:group>)
+ }
+ </xml:group>
+ }
+
+ override implicit def xmlToXmlOrJsCmd(in: NodeSeq): RenderOut = new RenderOut(Full(in), fixedRender, Empty, Empty, false)
+
+ override def lowPriority = {
+ case UserActor.MessageReceived(msg, _) =>
+ messages = (msg.id.is :: messages).take(40)
+ reRender(false)
+
+ case Distributor.UserUpdated(_) =>
+ reRender(false)
+ }
+}
Added: incubator/esme/trunk/server/src/main/scala/us/esme/external/TwitterFeed.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/external/TwitterFeed.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/external/TwitterFeed.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/external/TwitterFeed.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,56 @@
+package us.esme.external
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+import us.esme.actor.UniqueMessageSource
+import us.esme.actor.Distributor.UserCreatedMessage
+import us.esme.model.User
+
+import net.liftweb._
+import util._
+
+object TwitterFeed {
+ val UserTimelineUrl = "http://twitter.com/statuses/user_timeline/"
+ val Protocol = "xml"
+ val Params = ""
+ val tf = new java.text.SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", java.util.Locale.US)
+
+}
+
+class TwitterFeed(val user: User, val twitterUser: String) extends UniqueMessageSource {
+ import java.net.{URLConnection, URL}
+ import scala.xml._
+ import TwitterFeed._
+
+ override def apply() = {
+ val url = new URL(UserTimelineUrl + twitterUser + "." + Protocol + Params)
+ val conn = url.openConnection()
+
+
+ (for (node <- (XML.load(conn.getInputStream) \ "status")) yield UserCreatedMessage(
+ user.id,
+ node \ "text" text,
+ List("twitter"),
+ tf.parse(node \ "created_at" text).getTime,
+ Empty,
+ "twiiter",
+ Empty
+ )).toList
+ }
+
+}
+
Added: incubator/esme/trunk/server/src/main/scala/us/esme/lib/MsgFormat.scala
URL: http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/us/esme/lib/MsgFormat.scala?rev=726084&view=auto
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/us/esme/lib/MsgFormat.scala (added)
+++ incubator/esme/trunk/server/src/main/scala/us/esme/lib/MsgFormat.scala Fri Dec 12 10:32:17 2008
@@ -0,0 +1,111 @@
+
+/*
+ * Copyright 2008 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+package us.esme.lib
+
+import us.esme._
+import model._
+
+import scala.xml.{NodeSeq, Node, Text}
+
+import net.liftweb._
+import util._
+import http._
+import Helpers._
+
+import java.text.SimpleDateFormat
+
+object IsIE7 extends SessionVar[Boolean]({
+ // "Firefox/3"
+ // "MSIE 7"
+ def findUserAgent(in: List[(String, String)]): Can[String] =
+ in.filter(_._1.equalsIgnoreCase("User-Agent")).map(_._2).firstOption
+
+ val r: Can[Boolean] =
+ for (session <- S.session;
+ agent <- findUserAgent(session.initialHeaders)) yield
+ agent.indexOf("MSIE 7") >= 0
+
+ r openOr false
+})
+
+trait MsgFormat {
+
+ def formatMsg(in: Message, showReply: Boolean, showConv: Boolean): NodeSeq =
+ formatMsg(in, showReply, showConv, Empty)
+
+ def formatMsg(in: Message, showReply: Boolean, showConv: Boolean,
+ inside: Can[() => NodeSeq]): NodeSeq =
+ <div class="b-list">
+ <table>
+ <tr>
+ <td class="image">{
+ val r: Can[NodeSeq] =
+ for (user <- in.author.obj;
+ image <- user.image if !IsIE7.is) yield <img src={image} alt={user.niceName}/>
+
+ r openOr <xml:group> </xml:group>
+ }</td>
+ <td class="message">
+ <div class="outer">
+ <div class="inner clear">
+ <p class="text">{in.digestedXHTML}</p>
+ </div>
+ <p class="date">{in.author.obj.map(u => <a href={"/user/"+urlEncode(u.nickname)}>{u.niceName}</a>).openOr("")}:
+ { dateFormat(in.when)} {
+ if (showReply) <a href={"javascript:setReplyTo("+in.id+","+
+ in.getText.encJs+
+ ")"}>reply</a>
+ else Text("")
+
+ }
+ {
+ in.conversation.can.toList.map(cid => <a href={"/conversation/"+cid}>conversation</a>)
+ }
+ </p>
+ </div>
+ </td>
+ <td class="tag">
+ {
+ in.tags.map(tag => <p><a href={"/tag/"+urlEncode(tag)}>{tag}</a></p>)
+ }
+ </td>
+ </tr>
+ </table>
+ {
+ inside.map(_()).openOr(Text(""))
+ }
+ </div>
+
+ private def dateFormat(in: Long): String = {
+ val delta = ((millis - in) / 1000L).toInt
+
+ delta match {
+ case 1 => "1 Second ago"
+ case n if n < 60 => ""+n+" Seconds ago"
+ case n if n >= 60 && n < 120 => "1 Minute ago"
+ case n if n < 3600 => ""+(n / 60)+" Minutes ago"
+ case n =>
+ (n / 3600) match {
+ case 1 => "1 Hour ago"
+ case n if n < 24 => ""+n+" Hours ago"
+ case _ => val df = new SimpleDateFormat("MM/dd HH:mm zzz")
+ dateFormatter.format(new java.util.Date(in))
+ }
+ }
+ }
+}