[kune-commits] r1524 - in trunk/src: main/java/cc/kune/core/client/errors main/java/cc/kune/core/client/rpcservices main/java/cc/kune/core/client/sn/actions main/java/cc/kune/core/client/sn/actions/registry main/java/cc/kune/core/server main/java/cc/kune/core/server/content main/java/cc/kune/core/server/init main/java/cc/kune/core/server/manager main/java/cc/kune/core/server/manager/impl main/java/cc/kune/core/server/rpc main/java/cc/kune/core/server/state main/java/cc/kune/domain main/java/cc/kune/gspace/client main/java/cc/kune/lists/server main/java/cc/kune/wave/server main/resources test/java/cc/kune/wave/server

Vicente J. Ruiz Jurado vjrj_ at ourproject.org
Tue Sep 20 16:28:25 CEST 2011


Author: vjrj_
Date: 2011-09-20 16:28:24 +0200 (Tue, 20 Sep 2011)
New Revision: 1524

Added:
   trunk/src/main/java/cc/kune/core/client/sn/actions/EventTargetUtils.java
   trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToAction.java
   trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToAdmins.java
   trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToBuddieHeaderButton.java
   trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToMembers.java
   trunk/src/main/java/cc/kune/core/server/manager/KuneWaveManager.java
   trunk/src/main/java/cc/kune/core/server/manager/impl/KuneWaveManagerDefault.java
   trunk/src/main/java/cc/kune/wave/server/KuneWaveService.java
   trunk/src/main/java/cc/kune/wave/server/KuneWaveServiceDefault.java
   trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java
   trunk/src/test/java/cc/kune/wave/server/KuneWaveServiceDefaultTest.java
Removed:
   trunk/src/main/java/cc/kune/wave/server/KuneWaveManager.java
   trunk/src/main/java/cc/kune/wave/server/KuneWaveManagerDefault.java
   trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java
   trunk/src/test/java/cc/kune/wave/server/KuneWaveManagerDefaultTest.java
Modified:
   trunk/src/main/java/cc/kune/core/client/errors/AccessViolationException.java
   trunk/src/main/java/cc/kune/core/client/errors/ErrorHandler.java
   trunk/src/main/java/cc/kune/core/client/rpcservices/ContentService.java
   trunk/src/main/java/cc/kune/core/client/rpcservices/ContentServiceAsync.java
   trunk/src/main/java/cc/kune/core/client/sn/actions/GotoGroupAction.java
   trunk/src/main/java/cc/kune/core/client/sn/actions/registry/GroupSNAdminsMenuItemsRegistry.java
   trunk/src/main/java/cc/kune/core/client/sn/actions/registry/GroupSNCollabsMenuItemsRegistry.java
   trunk/src/main/java/cc/kune/core/client/sn/actions/registry/GroupSNConfActions.java
   trunk/src/main/java/cc/kune/core/client/sn/actions/registry/UserSNMenuItemsRegistry.java
   trunk/src/main/java/cc/kune/core/server/PlatformServerModule.java
   trunk/src/main/java/cc/kune/core/server/content/ContentManagerDefault.java
   trunk/src/main/java/cc/kune/core/server/content/CreationServiceDefault.java
   trunk/src/main/java/cc/kune/core/server/init/DatabaseInitializer.java
   trunk/src/main/java/cc/kune/core/server/manager/impl/UserManagerDefault.java
   trunk/src/main/java/cc/kune/core/server/rpc/ContentRPC.java
   trunk/src/main/java/cc/kune/core/server/state/StateServiceDefault.java
   trunk/src/main/java/cc/kune/domain/User.java
   trunk/src/main/java/cc/kune/gspace/client/GSpaceGinModule.java
   trunk/src/main/java/cc/kune/gspace/client/GSpaceParts.java
   trunk/src/main/java/cc/kune/lists/server/ListsServerTool.java
   trunk/src/main/java/cc/kune/wave/server/KuneAgent.java
   trunk/src/main/java/cc/kune/wave/server/ParticipantUtils.java
   trunk/src/main/resources/kune.properties
Log:
CLOSED - # 67: Write to this buddie/members/admins 
http://kune.ourproject.org/issues/ticket/67

Modified: trunk/src/main/java/cc/kune/core/client/errors/AccessViolationException.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/errors/AccessViolationException.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/client/errors/AccessViolationException.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -20,5 +20,13 @@
 package cc.kune.core.client.errors;
 
 public class AccessViolationException extends DefaultException {
-    private static final long serialVersionUID = -3786772632052256999L;
+  private static final long serialVersionUID = -3786772632052256999L;
+
+  public AccessViolationException() {
+    super();
+  }
+
+  public AccessViolationException(final String msg) {
+    super(msg);
+  }
 }

Modified: trunk/src/main/java/cc/kune/core/client/errors/ErrorHandler.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/errors/ErrorHandler.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/client/errors/ErrorHandler.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -82,8 +82,10 @@
     eventBus.fireEvent(new ProgressHideEvent());
     if (caught instanceof AccessViolationException) {
       logException(caught);
+      final String msg = caught.getMessage();
       eventBus.fireEvent(new UserNotifyEvent(NotifyLevel.error,
-          i18n.t("You do not have rights to perform that action")));
+          i18n.t("You do not have rights to perform that action")
+              + (TextUtils.empty(msg) ? "" : ". " + i18n.t(msg))));
       goHome();
     } else if (caught instanceof SessionExpiredException) {
       logException(caught);

Modified: trunk/src/main/java/cc/kune/core/client/rpcservices/ContentService.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/rpcservices/ContentService.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/client/rpcservices/ContentService.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -88,4 +88,6 @@
   StateAbstractDTO setStatusAsAdmin(String userHash, StateToken stateToken, ContentStatus status);
 
   TagCloudResult setTags(String userHash, StateToken token, String tags) throws DefaultException;
+
+  String writeTo(String userHash, StateToken token, boolean onlyToAdmins) throws DefaultException;
 }

Modified: trunk/src/main/java/cc/kune/core/client/rpcservices/ContentServiceAsync.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/rpcservices/ContentServiceAsync.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/client/rpcservices/ContentServiceAsync.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -97,4 +97,6 @@
   void setTags(String userHash, StateToken token, String tags,
       AsyncCallback<TagCloudResult> asyncCallback);
 
+  void writeTo(String userHash, StateToken token, boolean onlyToAdmins, AsyncCallback<String> callback);
+
 }

Added: trunk/src/main/java/cc/kune/core/client/sn/actions/EventTargetUtils.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/sn/actions/EventTargetUtils.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/client/sn/actions/EventTargetUtils.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -0,0 +1,28 @@
+package cc.kune.core.client.sn.actions;
+
+import cc.kune.common.client.actions.ActionEvent;
+import cc.kune.core.shared.domain.utils.StateToken;
+import cc.kune.core.shared.dto.GroupDTO;
+import cc.kune.core.shared.dto.UserSimpleDTO;
+
+public class EventTargetUtils {
+
+  public static StateToken getTargetToken(final ActionEvent event) {
+    StateToken token;
+    final Object target = event.getTarget();
+    if (target instanceof GroupDTO) {
+      token = ((GroupDTO) target).getStateToken();
+    } else {
+      token = ((UserSimpleDTO) target).getStateToken();
+    }
+    return token;
+  }
+
+  public static boolean isPerson(final ActionEvent event) {
+    final Object target = event.getTarget();
+    final boolean isUserDTO = target instanceof UserSimpleDTO;
+    final boolean isGroup = target instanceof GroupDTO;
+    return isUserDTO || (isGroup && ((GroupDTO) target).isPersonal());
+  }
+
+}

Modified: trunk/src/main/java/cc/kune/core/client/sn/actions/GotoGroupAction.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/sn/actions/GotoGroupAction.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/client/sn/actions/GotoGroupAction.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -24,34 +24,25 @@
 import cc.kune.common.client.actions.ActionEvent;
 import cc.kune.core.client.resources.CoreResources;
 import cc.kune.core.client.state.StateManager;
-import cc.kune.core.shared.domain.utils.StateToken;
-import cc.kune.core.shared.dto.GroupDTO;
-import cc.kune.core.shared.dto.UserSimpleDTO;
 import cc.kune.core.shared.i18n.I18nTranslationService;
 
 import com.google.inject.Inject;
 
 public class GotoGroupAction extends AbstractExtendedAction {
 
-    private final StateManager stateManager;
+  private final StateManager stateManager;
 
-    @Inject
-    public GotoGroupAction(final StateManager stateManager, final I18nTranslationService i18n, final CoreResources res) {
-        this.stateManager = stateManager;
-        putValue(NAME, i18n.t("Visit this group homepage"));
-        putValue(Action.SMALL_ICON, res.groupHome());
-    }
+  @Inject
+  public GotoGroupAction(final StateManager stateManager, final I18nTranslationService i18n,
+      final CoreResources res) {
+    this.stateManager = stateManager;
+    putValue(NAME, i18n.t("Visit this group homepage"));
+    putValue(Action.SMALL_ICON, res.groupHome());
+  }
 
-    @Override
-    public void actionPerformed(final ActionEvent event) {
-        StateToken token;
-        final Object target = event.getTarget();
-        if (target instanceof GroupDTO) {
-            token = ((GroupDTO) target).getStateToken();
-        } else {
-            token = ((UserSimpleDTO) target).getStateToken();
-        }
-        stateManager.gotoStateToken(token);
-    }
+  @Override
+  public void actionPerformed(final ActionEvent event) {
+    stateManager.gotoStateToken(EventTargetUtils.getTargetToken(event));
+  }
 
 }

Added: trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToAction.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToAction.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToAction.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -0,0 +1,77 @@
+package cc.kune.core.client.sn.actions;
+
+import cc.kune.common.client.actions.AbstractAction;
+import cc.kune.common.client.actions.AbstractExtendedAction;
+import cc.kune.common.client.actions.ActionEvent;
+import cc.kune.common.client.notify.NotifyUser;
+import cc.kune.common.client.utils.SimpleResponseCallback;
+import cc.kune.core.client.resources.nav.NavResources;
+import cc.kune.core.client.rpcservices.AsyncCallbackSimple;
+import cc.kune.core.client.rpcservices.ContentServiceAsync;
+import cc.kune.core.client.state.Session;
+import cc.kune.core.client.state.StateManager;
+import cc.kune.core.shared.domain.utils.StateToken;
+import cc.kune.core.shared.i18n.I18nTranslationService;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+public class WriteToAction extends AbstractExtendedAction {
+
+  private final Provider<ContentServiceAsync> contentService;
+  private final I18nTranslationService i18n;
+  private boolean onlyToAdmins;
+  private final Session session;
+  private final StateManager stateManager;
+
+  @Inject
+  public WriteToAction(final Provider<ContentServiceAsync> contentService,
+      final I18nTranslationService i18n, final Session session, final StateManager stateManager,
+      final NavResources res) {
+    this.contentService = contentService;
+    this.i18n = i18n;
+    this.session = session;
+    this.stateManager = stateManager;
+    onlyToAdmins = false;
+    putValue(AbstractAction.SMALL_ICON, res.pageText());
+  }
+
+  @Override
+  public void actionPerformed(final ActionEvent event) {
+    boolean isPerson = false;
+    final StateToken token;
+    if (event.getTarget() == null) {
+      token = session.getCurrentStateToken();
+    } else {
+      isPerson = EventTargetUtils.isPerson(event);
+      token = EventTargetUtils.getTargetToken(event);
+    }
+    NotifyUser.askConfirmation(
+        i18n.t("Confirm, please:"),
+        isPerson ? i18n.t("Do you want to write a message to your buddy?")
+            : onlyToAdmins ? i18n.t("Do you want to write a message to the admins of this group?")
+                : i18n.t("Do you want to write a message to the members of this group?"),
+        new SimpleResponseCallback() {
+          @Override
+          public void onCancel() {
+            // Do nothing
+          }
+
+          @Override
+          public void onSuccess() {
+            contentService.get().writeTo(session.getUserHash(), token, onlyToAdmins,
+                new AsyncCallbackSimple<String>() {
+                  @Override
+                  public void onSuccess(final String url) {
+                    stateManager.gotoHistoryToken(url);
+                    NotifyUser.info("Now you can edit this message");
+                  }
+                });
+          }
+        });
+  }
+
+  public void setOnlyToAdmin(final boolean onlyToAdmins) {
+    this.onlyToAdmins = onlyToAdmins;
+  }
+}

Added: trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToAdmins.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToAdmins.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToAdmins.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -0,0 +1,38 @@
+/*
+ *
+ * Copyright (C) 2007-2011 The kune development team (see CREDITS for details)
+ * This file is part of kune.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package cc.kune.core.client.sn.actions;
+
+import cc.kune.common.client.actions.ui.descrip.MenuItemDescriptor;
+import cc.kune.core.client.sn.actions.registry.GroupSNConfActions;
+import cc.kune.core.shared.i18n.I18nTranslationService;
+
+import com.google.inject.Inject;
+
+public class WriteToAdmins extends MenuItemDescriptor {
+
+  @Inject
+  public WriteToAdmins(final WriteToAction action, final I18nTranslationService i18n) {
+    super(action);
+    action.setOnlyToAdmin(true);
+    withText(i18n.t("Write to the admins of this group"));
+    setParent(GroupSNConfActions.OPTIONS_MENU);
+    setPosition(0);
+  }
+}

Added: trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToBuddieHeaderButton.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToBuddieHeaderButton.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToBuddieHeaderButton.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright (C) 2007-2011 The kune development team (see CREDITS for details)
+ * This file is part of kune.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package cc.kune.core.client.sn.actions;
+
+import cc.kune.chat.client.ChatClient;
+import cc.kune.common.client.actions.AbstractAction;
+import cc.kune.common.client.actions.PropertyChangeEvent;
+import cc.kune.common.client.actions.PropertyChangeListener;
+import cc.kune.common.client.actions.ui.descrip.ButtonDescriptor;
+import cc.kune.core.client.state.Session;
+import cc.kune.core.client.state.StateChangedEvent;
+import cc.kune.core.client.state.StateChangedEvent.StateChangedHandler;
+import cc.kune.core.client.state.StateManager;
+import cc.kune.core.client.ws.entheader.EntityHeader;
+import cc.kune.core.shared.dto.GroupDTO;
+import cc.kune.core.shared.dto.StateAbstractDTO;
+
+import com.google.inject.Inject;
+
+public class WriteToBuddieHeaderButton {
+
+  @Inject
+  public WriteToBuddieHeaderButton(final WriteToAction writeToAction, final EntityHeader entityHeader,
+      final StateManager stateManager, final Session session, final ChatClient chatEngine) {
+    final ButtonDescriptor button = new ButtonDescriptor(writeToAction);
+    // button.setVisible(false);
+    button.withText("Write to your buddie");
+    // button.setStyles("k-chat-add-as-buddie");
+    writeToAction.addPropertyChangeListener(new PropertyChangeListener() {
+      @Override
+      public void propertyChange(final PropertyChangeEvent event) {
+        if (event.getPropertyName().equals(AbstractAction.ENABLED)) {
+          button.setVisible((Boolean) event.getNewValue());
+        }
+      }
+    });
+    entityHeader.addAction(button);
+    stateManager.onStateChanged(true, new StateChangedHandler() {
+      @Override
+      public void onStateChanged(final StateChangedEvent event) {
+        final StateAbstractDTO state = event.getState();
+        final GroupDTO group = state.getGroup();
+        final String groupName = group.getShortName();
+        final boolean imLogged = session.isLogged();
+        final boolean isBuddie = chatEngine.isBuddie(groupName);
+        if (imLogged && group.isPersonal() && isBuddie
+            && !session.getCurrentUser().getShortName().equals(groupName)) {
+          button.setTarget(group);
+          writeToAction.setEnabled(true);
+        } else {
+          writeToAction.setEnabled(false);
+        }
+      }
+    });
+  }
+}
\ No newline at end of file

Added: trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToMembers.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToMembers.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/client/sn/actions/WriteToMembers.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -0,0 +1,38 @@
+/*
+ *
+ * Copyright (C) 2007-2011 The kune development team (see CREDITS for details)
+ * This file is part of kune.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package cc.kune.core.client.sn.actions;
+
+import cc.kune.common.client.actions.ui.descrip.MenuItemDescriptor;
+import cc.kune.core.client.sn.actions.registry.GroupSNConfActions;
+import cc.kune.core.shared.i18n.I18nTranslationService;
+
+import com.google.inject.Inject;
+
+public class WriteToMembers extends MenuItemDescriptor {
+
+  @Inject
+  public WriteToMembers(final WriteToAction action, final I18nTranslationService i18n) {
+    super(action);
+    action.setOnlyToAdmin(false);
+    withText(i18n.t("Write to the members of this group"));
+    setParent(GroupSNConfActions.OPTIONS_MENU);
+    setPosition(0);
+  }
+}

Modified: trunk/src/main/java/cc/kune/core/client/sn/actions/registry/GroupSNAdminsMenuItemsRegistry.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/sn/actions/registry/GroupSNAdminsMenuItemsRegistry.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/client/sn/actions/registry/GroupSNAdminsMenuItemsRegistry.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -19,6 +19,7 @@
  */
 package cc.kune.core.client.sn.actions.registry;
 
+import cc.kune.chat.client.actions.conditions.IsBuddieCondition;
 import cc.kune.common.client.actions.ui.descrip.MenuItemDescriptor;
 import cc.kune.core.client.sn.actions.AcceptJoinGroupAction;
 import cc.kune.core.client.sn.actions.ChangeToAdminAction;
@@ -28,6 +29,7 @@
 import cc.kune.core.client.sn.actions.GotoMemberAction;
 import cc.kune.core.client.sn.actions.GotoYourHomePageAction;
 import cc.kune.core.client.sn.actions.RemoveMemberAction;
+import cc.kune.core.client.sn.actions.WriteToAction;
 import cc.kune.core.client.sn.actions.conditions.IsCurrentStateAdministrableCondition;
 import cc.kune.core.client.sn.actions.conditions.IsGroupCondition;
 import cc.kune.core.client.sn.actions.conditions.IsLoggedCondition;
@@ -35,65 +37,81 @@
 import cc.kune.core.client.sn.actions.conditions.IsNotMeCondition;
 import cc.kune.core.client.sn.actions.conditions.IsPersonCondition;
 import cc.kune.core.client.state.Session;
+import cc.kune.core.shared.i18n.I18nTranslationService;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
 public class GroupSNAdminsMenuItemsRegistry extends AbstractSNMembersActionsRegistry {
 
-    @Inject
-    public GroupSNAdminsMenuItemsRegistry(final Session session, final IsLoggedCondition isLogged,
-            final IsCurrentStateAdministrableCondition isAdministrableCondition, final IsPersonCondition isPersonCondition,
-            final IsGroupCondition isGroupCondition, final IsMeCondition isMe, final IsNotMeCondition isNotMe,
-            final ChangeToCollabAction changeToCollabAction, final ChangeToAdminAction changeToAdminAction,
-            final RemoveMemberAction removeMemberAction, final AcceptJoinGroupAction acceptJoinGroupAction,
-            final DenyJoinGroupAction denyJoinGroupAction, final GotoGroupAction gotoGroupAction,
-            final GotoMemberAction gotoMemberAction, final GotoYourHomePageAction gotoYourHomePageAction) {
-        add(new Provider<MenuItemDescriptor>() {
-            @Override
-            public MenuItemDescriptor get() {
-                final MenuItemDescriptor item = new MenuItemDescriptor(gotoMemberAction);
-                item.add(isPersonCondition);
-                item.add(isNotMe);
-                return item;
-            }
-        });
-        add(new Provider<MenuItemDescriptor>() {
-            @Override
-            public MenuItemDescriptor get() {
-                final MenuItemDescriptor item = new MenuItemDescriptor(gotoYourHomePageAction);
-                item.add(isPersonCondition);
-                item.add(isMe);
-                return item;
-            }
-        });
-        add(new Provider<MenuItemDescriptor>() {
-            @Override
-            public MenuItemDescriptor get() {
-                final MenuItemDescriptor item = new MenuItemDescriptor(gotoGroupAction);
-                item.add(isGroupCondition);
-                return item;
-            }
-        });
-        add(new Provider<MenuItemDescriptor>() {
-            @Override
-            public MenuItemDescriptor get() {
-                final MenuItemDescriptor item = new MenuItemDescriptor(changeToCollabAction);
-                item.add(isAdministrableCondition);
-                item.add(isNotMe);
-                item.add(isLogged);
-                return item;
-            }
-        });
-        add(new Provider<MenuItemDescriptor>() {
-            @Override
-            public MenuItemDescriptor get() {
-                final MenuItemDescriptor item = new MenuItemDescriptor(removeMemberAction);
-                item.add(isAdministrableCondition);
-                item.add(isNotMe);
-                item.add(isLogged);
-                return item;
-            }
-        });
-    }
+  @Inject
+  public GroupSNAdminsMenuItemsRegistry(final Session session, final I18nTranslationService i18n,
+      final IsLoggedCondition isLogged,
+      final IsCurrentStateAdministrableCondition isAdministrable,
+      final IsPersonCondition isPerson, final IsGroupCondition isGroup,
+      final IsBuddieCondition isBuddie, final IsMeCondition isMe, final IsNotMeCondition isNotMe,
+      final ChangeToCollabAction changeToCollabAction, final ChangeToAdminAction changeToAdminAction,
+      final RemoveMemberAction removeMemberAction, final AcceptJoinGroupAction acceptJoinGroupAction,
+      final DenyJoinGroupAction denyJoinGroupAction, final GotoGroupAction gotoGroupAction,
+      final GotoMemberAction gotoMemberAction, final GotoYourHomePageAction gotoYourHomePageAction,
+      final WriteToAction writeToAction) {
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(gotoMemberAction);
+        item.add(isPerson);
+        item.add(isNotMe);
+        return item;
+      }
+    });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(gotoYourHomePageAction);
+        item.add(isPerson);
+        item.add(isMe);
+        return item;
+      }
+    });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(writeToAction);
+        item.add(isPerson);
+        item.withText(i18n.t("Write to your buddie"));
+        item.add(isNotMe);
+        item.add(isBuddie);
+        item.add(isLogged);
+        return item;
+      }
+    });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(gotoGroupAction);
+        item.add(isGroup);
+        return item;
+      }
+    });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(changeToCollabAction);
+        item.add(isAdministrable);
+        item.add(isNotMe);
+        item.add(isLogged);
+        return item;
+      }
+    });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(removeMemberAction);
+        item.add(isAdministrable);
+        item.add(isNotMe);
+        item.add(isLogged);
+        return item;
+      }
+    });
+  }
 }

Modified: trunk/src/main/java/cc/kune/core/client/sn/actions/registry/GroupSNCollabsMenuItemsRegistry.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/sn/actions/registry/GroupSNCollabsMenuItemsRegistry.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/client/sn/actions/registry/GroupSNCollabsMenuItemsRegistry.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -19,6 +19,7 @@
  */
 package cc.kune.core.client.sn.actions.registry;
 
+import cc.kune.chat.client.actions.conditions.IsBuddieCondition;
 import cc.kune.common.client.actions.ui.descrip.MenuItemDescriptor;
 import cc.kune.core.client.sn.actions.AcceptJoinGroupAction;
 import cc.kune.core.client.sn.actions.ChangeToAdminAction;
@@ -28,69 +29,87 @@
 import cc.kune.core.client.sn.actions.GotoMemberAction;
 import cc.kune.core.client.sn.actions.GotoYourHomePageAction;
 import cc.kune.core.client.sn.actions.RemoveMemberAction;
+import cc.kune.core.client.sn.actions.WriteToAction;
 import cc.kune.core.client.sn.actions.conditions.IsCurrentStateAdministrableCondition;
 import cc.kune.core.client.sn.actions.conditions.IsGroupCondition;
+import cc.kune.core.client.sn.actions.conditions.IsLoggedCondition;
 import cc.kune.core.client.sn.actions.conditions.IsMeCondition;
 import cc.kune.core.client.sn.actions.conditions.IsNotMeCondition;
 import cc.kune.core.client.sn.actions.conditions.IsPersonCondition;
 import cc.kune.core.client.state.Session;
+import cc.kune.core.shared.i18n.I18nTranslationService;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
 public class GroupSNCollabsMenuItemsRegistry extends AbstractSNMembersActionsRegistry {
 
-    @Inject
-    public GroupSNCollabsMenuItemsRegistry(final Session session, final IsCurrentStateAdministrableCondition isAdministrableCondition,
-            final IsPersonCondition isPersonCondition, final IsGroupCondition isGroupCondition,
-            final IsMeCondition isMe, final IsNotMeCondition isNotMe, final ChangeToCollabAction changeToCollabAction,
-            final ChangeToAdminAction changeToAdminAction, final RemoveMemberAction removeMemberAction,
-            final AcceptJoinGroupAction acceptJoinGroupAction, final DenyJoinGroupAction denyJoinGroupAction,
-            final GotoGroupAction gotoGroupAction, final GotoMemberAction gotoMemberAction,
-            final GotoYourHomePageAction gotoYourHomePageAction) {
-        add(new Provider<MenuItemDescriptor>() {
-            @Override
-            public MenuItemDescriptor get() {
-                final MenuItemDescriptor item = new MenuItemDescriptor(changeToAdminAction);
-                item.add(isAdministrableCondition);
-                return item;
-            }
-        });
-        add(new Provider<MenuItemDescriptor>() {
-            @Override
-            public MenuItemDescriptor get() {
-                final MenuItemDescriptor item = new MenuItemDescriptor(removeMemberAction);
-                item.add(isAdministrableCondition);
-                return item;
-            }
-        });
-        add(new Provider<MenuItemDescriptor>() {
-            @Override
-            public MenuItemDescriptor get() {
-                final MenuItemDescriptor item = new MenuItemDescriptor(gotoMemberAction);
-                item.add(isPersonCondition);
-                item.add(isNotMe);
-                return item;
-            }
-        });
-        add(new Provider<MenuItemDescriptor>() {
-            @Override
-            public MenuItemDescriptor get() {
-                final MenuItemDescriptor item = new MenuItemDescriptor(gotoYourHomePageAction);
-                item.add(isPersonCondition);
-                item.add(isMe);
-                return item;
-            }
-        });
-        add(new Provider<MenuItemDescriptor>() {
-            @Override
-            public MenuItemDescriptor get() {
-                final MenuItemDescriptor item = new MenuItemDescriptor(gotoGroupAction);
-                item.add(isGroupCondition);
-                return item;
-            }
-        });
+  @Inject
+  public GroupSNCollabsMenuItemsRegistry(final Session session, final I18nTranslationService i18n,
+      final IsLoggedCondition isLogged,
+      final IsCurrentStateAdministrableCondition isAdministrableCondition,
+      final IsPersonCondition isPersonCondition, final IsGroupCondition isGroupCondition,
+      final IsBuddieCondition isBuddie, final IsMeCondition isMe, final IsNotMeCondition isNotMe,
+      final ChangeToCollabAction changeToCollabAction, final ChangeToAdminAction changeToAdminAction,
+      final RemoveMemberAction removeMemberAction, final AcceptJoinGroupAction acceptJoinGroupAction,
+      final DenyJoinGroupAction denyJoinGroupAction, final GotoGroupAction gotoGroupAction,
+      final GotoMemberAction gotoMemberAction, final GotoYourHomePageAction gotoYourHomePageAction,
+      final WriteToAction writeToAction) {
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(changeToAdminAction);
+        item.add(isAdministrableCondition);
+        return item;
+      }
+    });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(removeMemberAction);
+        item.add(isAdministrableCondition);
+        return item;
+      }
+    });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(writeToAction);
+        item.add(isPersonCondition);
+        item.withText(i18n.t("Write to your buddie"));
+        item.add(isNotMe);
+        item.add(isBuddie);
+        item.add(isLogged);
+        return item;
+      }
+    });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(gotoMemberAction);
+        item.add(isPersonCondition);
+        item.add(isNotMe);
+        return item;
+      }
+    });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(gotoYourHomePageAction);
+        item.add(isPersonCondition);
+        item.add(isMe);
+        return item;
+      }
+    });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(gotoGroupAction);
+        item.add(isGroupCondition);
+        return item;
+      }
+    });
 
-    }
+  }
 
 }

Modified: trunk/src/main/java/cc/kune/core/client/sn/actions/registry/GroupSNConfActions.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/sn/actions/registry/GroupSNConfActions.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/client/sn/actions/registry/GroupSNConfActions.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -31,6 +31,8 @@
 import cc.kune.core.client.sn.actions.MembersModerationMenuItem;
 import cc.kune.core.client.sn.actions.MembersVisibilityMenuItem;
 import cc.kune.core.client.sn.actions.UnJoinFromCurrentGroupAction;
+import cc.kune.core.client.sn.actions.WriteToAdmins;
+import cc.kune.core.client.sn.actions.WriteToMembers;
 import cc.kune.core.client.sn.actions.conditions.IsGroupCondition;
 import cc.kune.core.client.sn.actions.conditions.IsLoggedCondition;
 import cc.kune.core.client.state.Session;
@@ -66,6 +68,7 @@
       final I18nTranslationService i18n, final Provider<MembersVisibilityMenuItem> membersVisibility,
       final Provider<MembersModerationMenuItem> membersModeration, final CoreResources res,
       final IsLoggedCondition isLoggedCondition, final JoinGroupAction joinGroupAction,
+      final WriteToMembers writeToMembers, final WriteToAdmins writeToAdmins,
       final IsGroupCondition isGroupCondition, final UnJoinFromCurrentGroupAction unJoinGroupAction) {
     OPTIONS_MENU.withToolTip(i18n.t("Options")).withIcon(res.arrowdownsitebar()).withStyles(
         OPTIONS_STYLES);

Modified: trunk/src/main/java/cc/kune/core/client/sn/actions/registry/UserSNMenuItemsRegistry.java
===================================================================
--- trunk/src/main/java/cc/kune/core/client/sn/actions/registry/UserSNMenuItemsRegistry.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/client/sn/actions/registry/UserSNMenuItemsRegistry.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -19,6 +19,7 @@
  */
 package cc.kune.core.client.sn.actions.registry;
 
+import cc.kune.chat.client.actions.conditions.IsBuddieCondition;
 import cc.kune.common.client.actions.ui.descrip.MenuItemDescriptor;
 import cc.kune.core.client.sn.actions.AcceptJoinGroupAction;
 import cc.kune.core.client.sn.actions.ChangeToAdminAction;
@@ -29,6 +30,7 @@
 import cc.kune.core.client.sn.actions.GotoYourHomePageAction;
 import cc.kune.core.client.sn.actions.RemoveMemberAction;
 import cc.kune.core.client.sn.actions.UnJoinFromThisGroupAction;
+import cc.kune.core.client.sn.actions.WriteToAction;
 import cc.kune.core.client.sn.actions.conditions.ImPartOfGroupCondition;
 import cc.kune.core.client.sn.actions.conditions.IsCurrentStateAdministrableCondition;
 import cc.kune.core.client.sn.actions.conditions.IsGroupCondition;
@@ -37,6 +39,7 @@
 import cc.kune.core.client.sn.actions.conditions.IsNotMeCondition;
 import cc.kune.core.client.sn.actions.conditions.IsPersonCondition;
 import cc.kune.core.client.state.Session;
+import cc.kune.core.shared.i18n.I18nTranslationService;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -45,21 +48,22 @@
 public class UserSNMenuItemsRegistry extends AbstractSNMembersActionsRegistry {
 
   @Inject
-  public UserSNMenuItemsRegistry(final Session session,
+  public UserSNMenuItemsRegistry(final Session session, final I18nTranslationService i18n,
       final IsCurrentStateAdministrableCondition isAdministrableCondition,
-      final IsPersonCondition isPersonCondition, final IsGroupCondition isGroupCondition,
-      final ImPartOfGroupCondition imPartOfGroup, final IsLoggedCondition isLoggedCondition,
-      final IsMeCondition isMe, final IsNotMeCondition isNotMe,
+      final IsPersonCondition isPerson, final IsGroupCondition isGroup,
+      final ImPartOfGroupCondition imPartOfGroup, final IsLoggedCondition isLogged,
+      final IsBuddieCondition isBuddie, final IsMeCondition isMe, final IsNotMeCondition isNotMe,
       final ChangeToCollabAction changeToCollabAction, final ChangeToAdminAction changeToAdminAction,
       final RemoveMemberAction removeMemberAction, final AcceptJoinGroupAction acceptJoinGroupAction,
       final DenyJoinGroupAction denyJoinGroupAction, final GotoGroupAction gotoGroupAction,
       final GotoPersonAction gotoPersonAction, final UnJoinFromThisGroupAction unjoinAction,
+      final WriteToAction writeToAction, final WriteToAction writeToActionOnlyAdmins,
       final GotoYourHomePageAction gotoYourHomePageAction) {
     add(new Provider<MenuItemDescriptor>() {
       @Override
       public MenuItemDescriptor get() {
         final MenuItemDescriptor item = new MenuItemDescriptor(gotoPersonAction);
-        item.add(isPersonCondition);
+        item.add(isPerson);
         item.add(isNotMe);
         return item;
       }
@@ -68,30 +72,63 @@
       @Override
       public MenuItemDescriptor get() {
         final MenuItemDescriptor item = new MenuItemDescriptor(gotoGroupAction);
-        item.add(isGroupCondition);
+        item.add(isGroup);
         return item;
       }
     });
     add(new Provider<MenuItemDescriptor>() {
       @Override
       public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(writeToAction);
+        item.add(isPerson);
+        item.withText(i18n.t("Write to your buddie"));
+        item.add(isBuddie);
+        item.add(isNotMe);
+        item.add(isLogged);
+        return item;
+      }
+    });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
         final MenuItemDescriptor item = new MenuItemDescriptor(gotoYourHomePageAction);
-        item.add(isPersonCondition);
+        item.add(isPerson);
         item.add(isMe);
         return item;
       }
     });
-    // This doesn't works, because its unregister from current state not
-    // from target group
     add(new Provider<MenuItemDescriptor>() {
       @Override
       public MenuItemDescriptor get() {
         final MenuItemDescriptor item = new MenuItemDescriptor(unjoinAction);
-        item.add(isLoggedCondition);
-        item.add(isGroupCondition);
+        item.add(isLogged);
+        item.add(isGroup);
         item.add(imPartOfGroup);
         return item;
       }
     });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        writeToActionOnlyAdmins.setOnlyToAdmin(true);
+        final MenuItemDescriptor item = new MenuItemDescriptor(writeToActionOnlyAdmins);
+        item.withText(i18n.t("Write to the admins of this group"));
+        item.add(isLogged);
+        item.add(isGroup);
+        item.add(imPartOfGroup);
+        return item;
+      }
+    });
+    add(new Provider<MenuItemDescriptor>() {
+      @Override
+      public MenuItemDescriptor get() {
+        final MenuItemDescriptor item = new MenuItemDescriptor(writeToAction);
+        item.withText(i18n.t("Write to the members of this group"));
+        item.add(isLogged);
+        item.add(isGroup);
+        item.add(imPartOfGroup);
+        return item;
+      }
+    });
   }
 }

Modified: trunk/src/main/java/cc/kune/core/server/PlatformServerModule.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/PlatformServerModule.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/server/PlatformServerModule.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -57,6 +57,7 @@
 import cc.kune.core.server.manager.I18nCountryManager;
 import cc.kune.core.server.manager.I18nLanguageManager;
 import cc.kune.core.server.manager.I18nTranslationManager;
+import cc.kune.core.server.manager.KuneWaveManager;
 import cc.kune.core.server.manager.LicenseManager;
 import cc.kune.core.server.manager.RateManager;
 import cc.kune.core.server.manager.SocialNetworkManager;
@@ -75,6 +76,7 @@
 import cc.kune.core.server.manager.impl.I18nCountryManagerDefault;
 import cc.kune.core.server.manager.impl.I18nLanguageManagerDefault;
 import cc.kune.core.server.manager.impl.I18nTranslationManagerDefault;
+import cc.kune.core.server.manager.impl.KuneWaveManagerDefault;
 import cc.kune.core.server.manager.impl.LicenseManagerDefault;
 import cc.kune.core.server.manager.impl.RateManagerDefault;
 import cc.kune.core.server.manager.impl.SocialNetworkManagerDefault;
@@ -102,8 +104,8 @@
 import cc.kune.domain.SocialNetwork;
 import cc.kune.lists.client.rpc.ListsService;
 import cc.kune.lists.server.rpc.ListsRPC;
-import cc.kune.wave.server.KuneWaveManager;
-import cc.kune.wave.server.KuneWaveManagerDefault;
+import cc.kune.wave.server.KuneWaveService;
+import cc.kune.wave.server.KuneWaveServiceDefault;
 import cc.kune.wave.server.ParticipantUtils;
 
 import com.google.inject.matcher.Matchers;
@@ -158,6 +160,7 @@
     bind(StateService.class).to(StateServiceDefault.class);
     bind(I18nTranslationService.class).to(I18nTranslationServiceDefault.class);
     bind(SessionService.class).to(SessionServiceDefault.class);
+    bind(KuneWaveService.class).to(KuneWaveServiceDefault.class);
     bind(XMLActionReader.class);
   }
 

Modified: trunk/src/main/java/cc/kune/core/server/content/ContentManagerDefault.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/content/ContentManagerDefault.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/server/content/ContentManagerDefault.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -56,7 +56,7 @@
 import cc.kune.domain.finders.ContentFinder;
 import cc.kune.domain.finders.I18nLanguageFinder;
 import cc.kune.domain.finders.UserFinder;
-import cc.kune.wave.server.KuneWaveManager;
+import cc.kune.wave.server.KuneWaveService;
 import cc.kune.wave.server.KuneWaveUtils;
 import cc.kune.wave.server.ParticipantUtils;
 
@@ -70,7 +70,7 @@
   private final ContainerFinder containerFinder;
   private final ContentFinder contentFinder;
   private final FinderService finder;
-  private final KuneWaveManager kuneWaveManager;
+  private final KuneWaveService kuneWaveManager;
   private final I18nLanguageFinder languageFinder;
   private final ParticipantUtils participantUtils;
   private final TagUserContentManager tagManager;
@@ -80,7 +80,7 @@
   public ContentManagerDefault(final ContentFinder contentFinder, final ContainerFinder containerFinder,
       final Provider<EntityManager> provider, final FinderService finder, final UserFinder userFinder,
       final I18nLanguageFinder languageFinder, final TagUserContentManager tagManager,
-      final KuneWaveManager kuneWaveManager, final ParticipantUtils participantUtils) {
+      final KuneWaveService kuneWaveManager, final ParticipantUtils participantUtils) {
     super(provider, Content.class);
     this.contentFinder = contentFinder;
     this.containerFinder = containerFinder;
@@ -115,7 +115,7 @@
   @Override
   public Content createContent(final String title, final String body, final User author,
       final Container container, final String typeId) {
-    return createContent(title, body, author, container, typeId, KuneWaveManager.WITHOUT_GADGET);
+    return createContent(title, body, author, container, typeId, KuneWaveService.WITHOUT_GADGET);
   }
 
   @Override

Modified: trunk/src/main/java/cc/kune/core/server/content/CreationServiceDefault.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/content/CreationServiceDefault.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/server/content/CreationServiceDefault.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -35,7 +35,7 @@
 import cc.kune.domain.Group;
 import cc.kune.domain.I18nLanguage;
 import cc.kune.domain.User;
-import cc.kune.wave.server.KuneWaveManager;
+import cc.kune.wave.server.KuneWaveService;
 
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
@@ -65,7 +65,7 @@
     final ServerTool tool = tools.get(toolName);
     tool.checkTypesBeforeContentCreation(container.getTypeId(), typeId);
     final URL gagdetUrl = tool instanceof ServerWaveTool ? ((ServerWaveTool) tool).getGadgetUrl()
-        : KuneWaveManager.WITHOUT_GADGET;
+        : KuneWaveService.WITHOUT_GADGET;
     final Content content = contentManager.createContent(title, body, user, container, typeId, gagdetUrl);
     tool.onCreateContent(content, container);
     return content;

Modified: trunk/src/main/java/cc/kune/core/server/init/DatabaseInitializer.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/init/DatabaseInitializer.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/server/init/DatabaseInitializer.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -44,7 +44,7 @@
 import cc.kune.domain.I18nTranslation;
 import cc.kune.domain.License;
 import cc.kune.domain.User;
-import cc.kune.wave.server.KuneWaveManager;
+import cc.kune.wave.server.KuneWaveService;
 
 import com.google.inject.Inject;
 import com.google.inject.persist.Transactional;
@@ -53,7 +53,7 @@
   private final ContentManager contentManager;
   private final I18nCountryManager countryManager;
   private final GroupManager groupManager;
-  private final KuneWaveManager kuneWaveManager;
+  private final KuneWaveService kuneWaveManager;
   private final I18nLanguageManager languageManager;
   private final LicenseManager licenseManager;
   private final KuneBasicProperties properties;
@@ -65,7 +65,7 @@
       final GroupManager groupManager, final LicenseManager licenseManager,
       final I18nLanguageManager languageManager, final I18nCountryManager countryManager,
       final I18nTranslationManager translationManager, final ContentManager contentManager,
-      final KuneWaveManager kuneWaveManager) {
+      final KuneWaveService kuneWaveManager) {
     this.properties = properties;
     this.userManager = userManager;
     this.groupManager = groupManager;

Added: trunk/src/main/java/cc/kune/core/server/manager/KuneWaveManager.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/manager/KuneWaveManager.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/manager/KuneWaveManager.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -0,0 +1,11 @@
+package cc.kune.core.server.manager;
+
+import cc.kune.domain.User;
+
+public interface KuneWaveManager {
+
+  String sendFeedback(User user, String title, String body);
+
+  String writeTo(User user, String groupName, boolean onlyToAdmins);
+
+}

Added: trunk/src/main/java/cc/kune/core/server/manager/impl/KuneWaveManagerDefault.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/manager/impl/KuneWaveManagerDefault.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/manager/impl/KuneWaveManagerDefault.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -0,0 +1,84 @@
+package cc.kune.core.server.manager.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.waveprotocol.wave.model.wave.ParticipantId;
+
+import cc.kune.core.client.errors.AccessViolationException;
+import cc.kune.core.server.access.AccessRightsUtils;
+import cc.kune.core.server.manager.KuneWaveManager;
+import cc.kune.core.server.manager.UserManager;
+import cc.kune.core.server.properties.KuneProperties;
+import cc.kune.core.shared.domain.AccessRol;
+import cc.kune.domain.Group;
+import cc.kune.domain.User;
+import cc.kune.domain.finders.GroupFinder;
+import cc.kune.domain.utils.UserBuddiesData;
+import cc.kune.wave.server.KuneWaveService;
+import cc.kune.wave.server.KuneWaveUtils;
+import cc.kune.wave.server.ParticipantUtils;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+ at Singleton
+public class KuneWaveManagerDefault implements KuneWaveManager {
+
+  private final GroupFinder groupFinder;
+  private final KuneProperties kuneProperties;
+  private final ParticipantUtils participantUtils;
+  private final UserManager userManager;
+  private final KuneWaveService waveService;
+
+  @Inject
+  public KuneWaveManagerDefault(final KuneWaveService waveService,
+      final ParticipantUtils participantUtils, final KuneProperties kuneProperties,
+      final GroupFinder groupFinder, final UserManager userManager) {
+    this.waveService = waveService;
+    this.participantUtils = participantUtils;
+    this.kuneProperties = kuneProperties;
+    this.groupFinder = groupFinder;
+    this.userManager = userManager;
+  }
+
+  @Override
+  public String sendFeedback(final User user, final String title, final String body) {
+    final List<String> participants = kuneProperties.getList(KuneProperties.FEEDBACK_TO);
+    participants.add(0, user.getShortName());
+    final List<ParticipantId> partIds = new ArrayList<ParticipantId>();
+    for (final String part : participants) {
+      partIds.add(participantUtils.of(part));
+    }
+    return KuneWaveUtils.getUrl(waveService.createWave(title, body,
+        partIds.toArray(new ParticipantId[0])));
+  }
+
+  @Override
+  public String writeTo(final User user, final String groupName, final boolean onlyToAdmins) {
+    final Group group = groupFinder.findByShortName(groupName);
+    final Set<Group> toList = new HashSet<Group>();
+    toList.add(user.getUserGroup());
+    if (group.isPersonal()) {
+      final UserBuddiesData userBuddies = userManager.getUserBuddies(groupName);
+      if (userBuddies.contains(user.getShortName())) {
+        toList.add(group);
+      } else {
+        throw new AccessViolationException("You cannot write to non buddies");
+      }
+    } else {
+      if (!AccessRightsUtils.correctMember(user, group, AccessRol.Editor)) {
+        throw new AccessViolationException("You cannot write because you are not a member");
+      }
+      if (onlyToAdmins) {
+        toList.addAll(group.getSocialNetwork().getAccessLists().getAdmins().getList());
+      } else {
+        toList.addAll(group.getSocialNetwork().getAccessLists().getAdmins().getList());
+        toList.addAll(group.getSocialNetwork().getAccessLists().getEditors().getList());
+      }
+    }
+    return KuneWaveUtils.getUrl(waveService.createWave("", participantUtils.listFrom(toList)));
+  }
+}

Modified: trunk/src/main/java/cc/kune/core/server/manager/impl/UserManagerDefault.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/manager/impl/UserManagerDefault.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/server/manager/impl/UserManagerDefault.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -64,7 +64,7 @@
 import cc.kune.domain.finders.UserFinder;
 import cc.kune.domain.utils.UserBuddiesData;
 import cc.kune.wave.server.CustomUserRegistrationServlet;
-import cc.kune.wave.server.KuneWaveManager;
+import cc.kune.wave.server.KuneWaveService;
 import cc.kune.wave.server.ParticipantUtils;
 
 import com.google.inject.Inject;
@@ -78,7 +78,7 @@
   private final I18nCountryManager countryManager;
   private final GroupManager groupManager;
   private final I18nTranslationService i18n;
-  private final KuneWaveManager kuneWaveManager;
+  private final KuneWaveService kuneWaveManager;
   private final I18nLanguageManager languageManager;
   private final ParticipantUtils participantUtils;
   private final KuneBasicProperties properties;
@@ -92,7 +92,7 @@
       final I18nLanguageManager languageManager, final I18nCountryManager countryManager,
       final XmppManager xmppManager, final ChatProperties chatProperties,
       final I18nTranslationService i18n, final CustomUserRegistrationServlet waveUserRegister,
-      final AccountStore waveAccountStore, final KuneWaveManager kuneWaveManager,
+      final AccountStore waveAccountStore, final KuneWaveService kuneWaveManager,
       final ParticipantUtils participantUtils, final KuneBasicProperties properties,
       final GroupManager groupManager) {
     super(provider, User.class);

Modified: trunk/src/main/java/cc/kune/core/server/rpc/ContentRPC.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/rpc/ContentRPC.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/server/rpc/ContentRPC.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -19,15 +19,10 @@
  */
 package cc.kune.core.server.rpc;
 
-import java.util.ArrayList;
 import java.util.Date;
-import java.util.List;
 
 import javax.persistence.NoResultException;
 
-import org.waveprotocol.wave.model.wave.ParticipantId;
-import org.waveprotocol.wave.util.escapers.jvm.JavaWaverefEncoder;
-
 import cc.kune.chat.server.ChatManager;
 import cc.kune.core.client.errors.AccessViolationException;
 import cc.kune.core.client.errors.ContentNotFoundException;
@@ -48,9 +43,9 @@
 import cc.kune.core.server.content.ContentUtils;
 import cc.kune.core.server.content.CreationService;
 import cc.kune.core.server.manager.GroupManager;
+import cc.kune.core.server.manager.KuneWaveManager;
 import cc.kune.core.server.manager.TagUserContentManager;
 import cc.kune.core.server.mapper.Mapper;
-import cc.kune.core.server.properties.KuneProperties;
 import cc.kune.core.server.state.StateContainer;
 import cc.kune.core.server.state.StateContent;
 import cc.kune.core.server.state.StateService;
@@ -71,8 +66,6 @@
 import cc.kune.domain.Content;
 import cc.kune.domain.Group;
 import cc.kune.domain.User;
-import cc.kune.wave.server.KuneWaveManager;
-import cc.kune.wave.server.ParticipantUtils;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -86,14 +79,12 @@
   private final CreationService creationService;
   private final FinderService finderService;
   private final GroupManager groupManager;
-  private final KuneProperties kuneProperties;
-  private final KuneWaveManager kuneWaveManager;
   private final Mapper mapper;
-  private final ParticipantUtils participantUtils;
   private final AccessRightsService rightsService;
   private final StateService stateService;
   private final TagUserContentManager tagManager;
   private final Provider<UserSession> userSessionProvider;
+  private final KuneWaveManager waveManager;
 
   @Inject
   public ContentRPC(final FinderService finderService, final Provider<UserSession> userSessionProvider,
@@ -101,8 +92,7 @@
       final StateService stateService, final CreationService creationService,
       final GroupManager groupManager, final ContentManager contentManager,
       final ContainerManager containerManager, final TagUserContentManager tagManager,
-      final Mapper mapper, final ChatManager chatManager, final KuneWaveManager kuneWaveManager,
-      final KuneProperties kuneProperties, final ParticipantUtils participantUtils) {
+      final Mapper mapper, final ChatManager chatManager, final KuneWaveManager waveManager) {
     this.finderService = finderService;
     this.userSessionProvider = userSessionProvider;
     this.accessService = accessService;
@@ -115,9 +105,7 @@
     this.tagManager = tagManager;
     this.mapper = mapper;
     this.chatManager = chatManager;
-    this.kuneWaveManager = kuneWaveManager;
-    this.kuneProperties = kuneProperties;
-    this.participantUtils = participantUtils;
+    this.waveManager = waveManager;
   }
 
   @Override
@@ -455,14 +443,7 @@
   public String sendFeedback(final String userHash, final String title, final String body)
       throws DefaultException {
     final User user = getCurrentUser();
-    final List<String> participants = kuneProperties.getList(KuneProperties.FEEDBACK_TO);
-    participants.add(0, user.getShortName());
-    final List<ParticipantId> partIds = new ArrayList<ParticipantId>();
-    for (final String part : participants) {
-      partIds.add(participantUtils.of(part));
-    }
-    return JavaWaverefEncoder.encodeToUriPathSegment(kuneWaveManager.createWave(title, body,
-        partIds.toArray(new ParticipantId[0])));
+    return waveManager.sendFeedback(user, title, body);
   }
 
   @Override
@@ -536,4 +517,13 @@
     return getSummaryTags(group);
   }
 
+  @Override
+  @Authenticated
+  @Transactional
+  public String writeTo(final String userHash, final StateToken token, final boolean onlyToAdmins)
+      throws DefaultException {
+    final User user = getCurrentUser();
+    return waveManager.writeTo(user, token.getGroup(), onlyToAdmins);
+  }
+
 }

Modified: trunk/src/main/java/cc/kune/core/server/state/StateServiceDefault.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/state/StateServiceDefault.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/core/server/state/StateServiceDefault.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -35,7 +35,7 @@
 import cc.kune.domain.License;
 import cc.kune.domain.Revision;
 import cc.kune.domain.User;
-import cc.kune.wave.server.KuneWaveManager;
+import cc.kune.wave.server.KuneWaveService;
 
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
@@ -47,7 +47,7 @@
   private final ContentManager contentManager;
   private final GroupManager groupManager;
   private final I18nTranslationService i18n;
-  private final KuneWaveManager kuneWaveManager;
+  private final KuneWaveService kuneWaveManager;
   private final AccessRightsService rightsService;
   private final SocialNetworkManager socialNetworkManager;
   private final TagUserContentManager tagManager;
@@ -56,7 +56,7 @@
   public StateServiceDefault(final GroupManager groupManager,
       final SocialNetworkManager socialNetworkManager, final ContentManager contentManager,
       final TagUserContentManager tagManager, final AccessRightsService rightsService,
-      final I18nTranslationService i18n, final KuneWaveManager kuneWaveManager) {
+      final I18nTranslationService i18n, final KuneWaveService kuneWaveManager) {
     this.groupManager = groupManager;
     this.socialNetworkManager = socialNetworkManager;
     this.contentManager = contentManager;

Modified: trunk/src/main/java/cc/kune/domain/User.java
===================================================================
--- trunk/src/main/java/cc/kune/domain/User.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/domain/User.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -75,9 +75,6 @@
   @Column(nullable = false)
   private byte[] diggest;
 
-  // @OneToOne(cascade = CascadeType.REMOVE)
-  // private final CustomProperties customProperties;
-
   @Column(unique = true, nullable = false)
   @Email
   @Length(min = 1)
@@ -88,6 +85,9 @@
   @GeneratedValue
   private Long id;
 
+  // @OneToOne(cascade = CascadeType.REMOVE)
+  // private final CustomProperties customProperties;
+
   @ManyToOne
   @NotNull
   private I18nLanguage language;
@@ -125,23 +125,10 @@
   @OneToOne(cascade = CascadeType.REMOVE)
   private Group userGroup;
 
-  // @OneToOne
-  // @OnDelete(action = OnDeleteAction.CASCADE)
-  // private Properties properties;
-
   public User() {
     this(null, null, null, null, null, null, null, null, null);
   }
 
-  //
-  // public User(final String shortName, final String longName, final String
-  // email, final String passwd,
-  // final I18nLanguage language, final I18nCountry country, final TimeZone
-  // timezone) {
-  // this(shortName, longName, email, passwd, language, country, timezone,
-  // null);
-  // }
-
   public User(final String shortName, final String longName, final String email, final String passwd,
       final byte[] diggets, final byte[] salt, final I18nLanguage language, final I18nCountry country,
       final TimeZone timezone) {
@@ -162,6 +149,41 @@
     // this.properties = properties;
   }
 
+  // @OneToOne
+  // @OnDelete(action = OnDeleteAction.CASCADE)
+  // private Properties properties;
+
+  @Override
+  public boolean equals(final Object obj) {
+    if (this == obj) {
+      return true;
+    }
+    if (obj == null) {
+      return false;
+    }
+    if (getClass() != obj.getClass()) {
+      return false;
+    }
+    final User other = (User) obj;
+    if (shortName == null) {
+      if (other.shortName != null) {
+        return false;
+      }
+    } else if (!shortName.equals(other.shortName)) {
+      return false;
+    }
+    return true;
+  }
+
+  //
+  // public User(final String shortName, final String longName, final String
+  // email, final String passwd,
+  // final I18nLanguage language, final I18nCountry country, final TimeZone
+  // timezone) {
+  // this(shortName, longName, email, passwd, language, country, timezone,
+  // null);
+  // }
+
   public I18nCountry getCountry() {
     return country;
   }
@@ -174,14 +196,14 @@
     return diggest;
   }
 
+  public String getEmail() {
+    return email;
+  }
+
   // public CustomProperties getCustomProperties() {
   // return customProperties;
   // }
 
-  public String getEmail() {
-    return email;
-  }
-
   public boolean getHasLogo() {
     return hasLogo();
   }
@@ -207,14 +229,14 @@
     return password;
   }
 
+  public byte[] getSalt() {
+    return salt;
+  }
+
   // public Properties getProperties() {
   // return properties;
   // }
 
-  public byte[] getSalt() {
-    return salt;
-  }
-
   public String getShortName() {
     return shortName;
   }
@@ -236,6 +258,14 @@
     return userGroup;
   }
 
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((shortName == null) ? 0 : shortName.hashCode());
+    return result;
+  }
+
   @Transient
   public boolean hasLogo() {
     return getUserGroup().hasLogo();

Modified: trunk/src/main/java/cc/kune/gspace/client/GSpaceGinModule.java
===================================================================
--- trunk/src/main/java/cc/kune/gspace/client/GSpaceGinModule.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/gspace/client/GSpaceGinModule.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -22,6 +22,7 @@
 import cc.kune.common.client.ExtendedGinModule;
 import cc.kune.core.client.sitebar.search.SitebarSearchPanel;
 import cc.kune.core.client.sitebar.search.SitebarSearchPresenter;
+import cc.kune.core.client.sn.actions.WriteToBuddieHeaderButton;
 import cc.kune.gspace.client.actions.ContentViewerOptionsMenu;
 import cc.kune.gspace.client.actions.GiveUsFeedbackBtn;
 import cc.kune.gspace.client.actions.RenameAction;
@@ -186,6 +187,7 @@
     s(ContentViewerOptionsMenu.class);
     s(RenameAction.class);
     s(GiveUsFeedbackBtn.class);
+    s(WriteToBuddieHeaderButton.class);
 
     // LicenseWizard
     bindPresenter(LicenseWizardPresenter.class, LicenseWizardView.class, LicenseWizardPanel.class,

Modified: trunk/src/main/java/cc/kune/gspace/client/GSpaceParts.java
===================================================================
--- trunk/src/main/java/cc/kune/gspace/client/GSpaceParts.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/gspace/client/GSpaceParts.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -22,6 +22,7 @@
 import cc.kune.core.client.init.AppStartEvent;
 import cc.kune.core.client.init.AppStartEvent.AppStartHandler;
 import cc.kune.core.client.sitebar.search.SitebarSearchPresenter;
+import cc.kune.core.client.sn.actions.WriteToBuddieHeaderButton;
 import cc.kune.core.client.state.Session;
 import cc.kune.gspace.client.actions.GiveUsFeedbackBtn;
 import cc.kune.gspace.client.i18n.I18nToTranslateGridPanel;
@@ -70,7 +71,8 @@
       final Provider<SiteOptionsI18nTranslatorAction> transAction,
       final Provider<GiveUsFeedbackBtn> giveUsFeedback,
       final Provider<I18nToTranslateGridPanel> toTrans,
-      final Provider<I18nTranslatorTabsCollection> gtranslator) {
+      final Provider<I18nTranslatorTabsCollection> gtranslator,
+      final Provider<WriteToBuddieHeaderButton> writeToBuddie) {
 
     session.onAppStart(true, new AppStartHandler() {
       @Override
@@ -109,6 +111,9 @@
         if (event.getInitData().isFeedbackEnabled()) {
           giveUsFeedback.get();
         }
+
+        // Others
+        writeToBuddie.get();
       }
     });
   }

Modified: trunk/src/main/java/cc/kune/lists/server/ListsServerTool.java
===================================================================
--- trunk/src/main/java/cc/kune/lists/server/ListsServerTool.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/lists/server/ListsServerTool.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -43,7 +43,7 @@
 import cc.kune.domain.Content;
 import cc.kune.domain.Group;
 import cc.kune.domain.User;
-import cc.kune.wave.server.KuneWaveManager;
+import cc.kune.wave.server.KuneWaveService;
 import cc.kune.wave.server.KuneWaveUtils;
 
 import com.google.inject.Inject;
@@ -52,12 +52,12 @@
 public class ListsServerTool extends AbstractServerTool {
 
   private final Provider<UserSession> userSessionProvider;
-  private final KuneWaveManager waveManager;
+  private final KuneWaveService waveManager;
 
   @Inject
   public ListsServerTool(final ContentManager contentManager, final ContainerManager containerManager,
       final ToolConfigurationManager configurationManager, final I18nTranslationService i18n,
-      final Provider<UserSession> userSessionProvider, final KuneWaveManager waveManager) {
+      final Provider<UserSession> userSessionProvider, final KuneWaveService waveManager) {
     super(NAME, ROOT_NAME, TYPE_ROOT, Arrays.asList(TYPE_POST), Arrays.asList(TYPE_LIST),
         Arrays.asList(TYPE_LIST), Arrays.asList(TYPE_ROOT), contentManager, containerManager,
         configurationManager, i18n, ServerToolTarget.forGroups);

Modified: trunk/src/main/java/cc/kune/wave/server/KuneAgent.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/KuneAgent.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/wave/server/KuneAgent.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -39,7 +39,7 @@
 
 @SuppressWarnings("serial")
 @Singleton
-public class KuneAgent extends AbstractBaseRobotAgent implements KuneWaveManager {
+public class KuneAgent extends AbstractBaseRobotAgent implements KuneWaveService {
 
   private static final Logger LOG = Logger.getLogger(KuneAgent.class.getName());
 

Deleted: trunk/src/main/java/cc/kune/wave/server/KuneWaveManager.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/KuneWaveManager.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/wave/server/KuneWaveManager.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -1,61 +0,0 @@
-/*
- *
- * Copyright (C) 2007-2011 The kune development team (see CREDITS for details)
- * This file is part of kune.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package cc.kune.wave.server;
-
-import java.net.URL;
-
-import org.waveprotocol.wave.model.id.WaveId;
-import org.waveprotocol.wave.model.id.WaveletId;
-import org.waveprotocol.wave.model.wave.ParticipantId;
-import org.waveprotocol.wave.model.waveref.WaveRef;
-
-import com.google.wave.api.Wavelet;
-
-public interface KuneWaveManager {
-  public static final URL WITHOUT_GADGET = null;
-
-  void addGadget(WaveRef waveName, String author, String gadgetUrl);
-
-  void addParticipants(WaveRef waveName, String author, String userWhoAdd, String... newParticipants);
-
-  WaveRef createWave(String message, ParticipantId... participants);
-
-  WaveRef createWave(String title, String message, ParticipantId... participantsArray);
-
-  WaveRef createWave(String title, String message, String waveIdToCopy, URL gadgetUrl,
-      ParticipantId... participantsArray);
-
-  WaveRef createWave(String title, String message, URL gadgetUrl, ParticipantId... participantsArray);
-
-  void delParticipants(WaveRef waveName, String whoDel, String... participants);
-
-  Wavelet fetchWave(WaveId waveId, WaveletId waveletId, String author);
-
-  Wavelet fetchWave(WaveRef waveRef, String author);
-
-  boolean isParticipant(Wavelet wavelet, String user);
-
-  String render(Wavelet wavelet);
-
-  String render(WaveRef waveRef, String author);
-
-  void setTitle(WaveRef waveName, String title, String author);
-
-}

Deleted: trunk/src/main/java/cc/kune/wave/server/KuneWaveManagerDefault.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/KuneWaveManagerDefault.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/wave/server/KuneWaveManagerDefault.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -1,446 +0,0 @@
-/*
- *
- * Copyright (C) 2007-2011 The kune development team (see CREDITS for details)
- * This file is part of kune.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package cc.kune.wave.server;
-
-import java.net.URL;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.annotation.Nonnull;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.waveprotocol.box.server.CoreSettings;
-import org.waveprotocol.box.server.robots.OperationContextImpl;
-import org.waveprotocol.box.server.robots.OperationServiceRegistry;
-import org.waveprotocol.box.server.robots.util.ConversationUtil;
-import org.waveprotocol.box.server.robots.util.OperationUtil;
-import org.waveprotocol.box.server.waveserver.WaveletProvider;
-import org.waveprotocol.box.server.waveserver.WaveletProvider.SubmitRequestListener;
-import org.waveprotocol.wave.model.id.InvalidIdException;
-import org.waveprotocol.wave.model.id.WaveId;
-import org.waveprotocol.wave.model.id.WaveletId;
-import org.waveprotocol.wave.model.version.HashedVersion;
-import org.waveprotocol.wave.model.wave.ParticipantId;
-import org.waveprotocol.wave.model.waveref.WaveRef;
-
-import cc.kune.common.client.utils.TextUtils;
-import cc.kune.core.client.errors.DefaultException;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-import com.google.wave.api.Annotation;
-import com.google.wave.api.ApiIdSerializer;
-import com.google.wave.api.Blip;
-import com.google.wave.api.BlipContent;
-import com.google.wave.api.BlipData;
-import com.google.wave.api.BlipThread;
-import com.google.wave.api.Element;
-import com.google.wave.api.ElementType;
-import com.google.wave.api.FormElement;
-import com.google.wave.api.Gadget;
-import com.google.wave.api.Image;
-import com.google.wave.api.JsonRpcConstant.ParamsProperty;
-import com.google.wave.api.JsonRpcResponse;
-import com.google.wave.api.Line;
-import com.google.wave.api.OperationQueue;
-import com.google.wave.api.OperationRequest;
-import com.google.wave.api.OperationRequest.Parameter;
-import com.google.wave.api.ProtocolVersion;
-import com.google.wave.api.Range;
-import com.google.wave.api.Wavelet;
-import com.google.wave.api.data.converter.EventDataConverterManager;
-import com.google.wave.api.impl.DocumentModifyAction;
-import com.google.wave.api.impl.DocumentModifyAction.BundledAnnotation;
-import com.google.wave.api.impl.DocumentModifyAction.ModifyHow;
-import com.google.wave.api.impl.WaveletData;
-import com.google.wave.splash.rpc.ClientAction;
-import com.google.wave.splash.web.template.WaveRenderer;
-
-public class KuneWaveManagerDefault implements KuneWaveManager {
-  public static final Log LOG = LogFactory.getLog(KuneWaveManagerDefault.class);
-
-  // See: DocumentModifyServiceTest
-  private static final String NO_ANNOTATION_KEY = null;
-  private static final List<BundledAnnotation> NO_BUNDLED_ANNOTATIONS = Collections.emptyList();
-  private static final String NO_TITLE = "";
-  private static final List<String> NO_VALUES = Collections.<String> emptyList();
-  private static final String NO_WAVE_TO_COPY = null;
-
-  /**
-   * 
-   * Copy blips
-   * 
-   * @param fromBlip
-   * @param toBlip
-   * 
-   * @author yurize at apache.org (Yuri Zelikov)
-   * 
-   */
-  public static void copyWavelet(final Blip fromBlip, final Blip toBlip) {
-    for (final BlipContent blipContent : fromBlip.all().values()) {
-      toBlip.append(blipContent);
-    }
-    // Deep copy annotations
-    for (final Annotation annotation : fromBlip.getAnnotations()) {
-      final Range range = annotation.getRange();
-      try {
-        toBlip.range(range.getStart() + 1, range.getEnd() + 1).annotate(annotation.getName(),
-            annotation.getValue());
-      } catch (final IndexOutOfBoundsException e) {
-        // Don't copy faulty annotations
-      }
-    }
-  }
-
-  public static void copyWaveletElements(final Blip fromBlip, final Blip toBlip) {
-    // Deep copy form elements.
-    // DocumentModifyService don't permit this:
-    // "Can't insert other elements than text and gadgets at the moment");
-    for (final Entry<Integer, Element> entry : fromBlip.getElements().entrySet()) {
-      final ElementType type = entry.getValue().getType();
-      Element result = null;
-      if (FormElement.getFormElementTypes().contains(type)) {
-        result = new FormElement(type, entry.getValue().getProperties());
-      } else if (type == ElementType.GADGET) {
-        result = new Gadget(entry.getValue().getProperties());
-      } else if (type == ElementType.IMAGE) {
-        result = new Image(entry.getValue().getProperties());
-      } else if (type == ElementType.LINE) {
-        result = new Line(entry.getValue().getProperties());
-      } else {
-        result = new Element(type, entry.getValue().getProperties());
-      }
-      toBlip.append(result);
-    }
-  }
-
-  private final ConversationUtil conversationUtil;
-  private final EventDataConverterManager converterManager;
-  private final String domain;
-  private final OperationServiceRegistry operationRegistry;
-  private final ParticipantUtils participantUtils;
-  private final WaveletProvider waveletProvider;
-  private final WaveRenderer waveRenderer;
-
-  @Inject
-  public KuneWaveManagerDefault(final EventDataConverterManager converterManager,
-      @Named("DataApiRegistry") final OperationServiceRegistry operationRegistry,
-      final WaveletProvider waveletProvider, final ConversationUtil conversationUtil,
-      final ParticipantUtils participantUtils, final WaveRenderer waveRenderer,
-      @Named(CoreSettings.WAVE_SERVER_DOMAIN) final String domain) {
-    this.converterManager = converterManager;
-    this.waveletProvider = waveletProvider;
-    this.conversationUtil = conversationUtil;
-    this.operationRegistry = operationRegistry;
-    this.participantUtils = participantUtils;
-    this.waveRenderer = waveRenderer;
-    this.domain = domain;
-  }
-
-  @Override
-  public void addGadget(final WaveRef waveName, final String author, final String gadgetUrl) {
-    // See DocumentModifyServiceTest
-    final List<Element> elementsIn = Lists.newArrayListWithCapacity(1);
-    final Map<String, String> properties = Maps.newHashMap();
-    properties.put(Gadget.URL, gadgetUrl);
-    properties.put(Gadget.AUTHOR, participantUtils.of(author).getAddress());
-    final Gadget gadget = new Gadget(properties);
-
-    elementsIn.add(gadget);
-    final Wavelet wavelet = fetchWave(waveName, author);
-    final OperationQueue opQueue = new OperationQueue();
-    final Blip rootBlip = wavelet.getRootBlip();
-
-    opQueue.modifyDocument(rootBlip).addParameter(
-        Parameter.of(ParamsProperty.MODIFY_ACTION, new DocumentModifyAction(ModifyHow.INSERT, NO_VALUES,
-            NO_ANNOTATION_KEY, elementsIn, NO_BUNDLED_ANNOTATIONS, false)));
-    opQueue.modifyDocument(rootBlip).addParameter(Parameter.of(ParamsProperty.INDEX, 1));
-    doOperation(author, opQueue, "add gadget");
-  }
-
-  @Override
-  public void addParticipants(final WaveRef waveName, final String author, final String userWhoAdds,
-      final String... newLocalParticipants) {
-    final Wavelet wavelet = fetchWave(waveName, author);
-    final OperationQueue opQueue = new OperationQueue();
-
-    for (final String newLocalParticipant : newLocalParticipants) {
-      final String newPartWithDomain = participantUtils.of(newLocalParticipant).toString();
-      boolean mustAdd = true;
-      for (final String current : wavelet.getParticipants()) {
-        if (current.equals(newPartWithDomain)) {
-          // Current user is a participant already (issue #73)
-          mustAdd = false;
-          break;
-        }
-      }
-      if (mustAdd) {
-        opQueue.addParticipantToWavelet(wavelet, newPartWithDomain);
-      }
-    }
-    if (opQueue.getPendingOperations().size() > 0) {
-      final String whoAdd = wavelet.getParticipants().contains(participantUtils.of(userWhoAdds)) ? userWhoAdds
-          : author;
-      doOperation(whoAdd, opQueue, "add participant");
-    }
-  }
-
-  @Override
-  public WaveRef createWave(final String message, final ParticipantId... participants) {
-    return createWave(NO_TITLE, message, participants);
-  }
-
-  @Override
-  public WaveRef createWave(@Nonnull final String title, final String message,
-      @Nonnull final ParticipantId... participantsArray) {
-    return createWave(title, message, WITHOUT_GADGET, participantsArray);
-  }
-
-  @Override
-  public WaveRef createWave(@Nonnull final String title, final String message,
-      final String waveIdToCopy, final URL gadgetUrl, @Nonnull final ParticipantId... participantsArray) {
-    String newWaveId = null;
-    String newWaveletId = null;
-    final Set<String> participants = new HashSet<String>();
-    for (final ParticipantId participant : participantsArray) {
-      participants.add(participant.toString());
-    }
-    final ParticipantId user = participantsArray[0];
-    final OperationQueue opQueue = new OperationQueue();
-    final Wavelet newWavelet = opQueue.createWavelet(domain, participants);
-    opQueue.setTitleOfWavelet(newWavelet, title);
-    final Blip rootBlip = newWavelet.getRootBlip();
-    rootBlip.append(new com.google.wave.api.Markup(message).getText());
-
-    if (waveIdToCopy != NO_WAVE_TO_COPY) {
-      try {
-        WaveId copyWaveId;
-        copyWaveId = WaveId.ofChecked(domain, waveIdToCopy);
-        final Wavelet waveletToCopy = fetchWave(copyWaveId, WaveletId.of(domain, "conv+root"),
-            participantsArray[0].toString());
-        if (waveletToCopy != null) {
-          copyWavelet(waveletToCopy.getRootBlip(), rootBlip);
-        }
-      } catch (final InvalidIdException e) {
-        LOG.error("Error copying wave content", e);
-      } catch (final DefaultException e2) {
-        LOG.error("Error copying wave content", e2);
-      }
-    }
-
-    if (gadgetUrl != WITHOUT_GADGET) {
-      final Gadget gadget = new Gadget(gadgetUrl.toString());
-      rootBlip.append(gadget);
-    }
-
-    final OperationContextImpl context = new OperationContextImpl(waveletProvider,
-        converterManager.getEventDataConverter(ProtocolVersion.DEFAULT), conversationUtil);
-    for (final OperationRequest req : opQueue.getPendingOperations()) {
-      OperationUtil.executeOperation(req, operationRegistry, context, user);
-      final String reqId = req.getId();
-      final JsonRpcResponse response = context.getResponse(reqId);
-      if (response != null) {
-        if (response.isError()) {
-          onFailure(context.getResponse(reqId).getErrorMessage());
-        } else {
-          final Object responseWaveId = response.getData().get(ParamsProperty.WAVE_ID);
-          final Object responseWaveletId = response.getData().get(ParamsProperty.WAVELET_ID);
-          if (responseWaveId != null && responseWaveletId != null) {
-            // This is serialized use
-            // ApiIdSerializer.instance().deserialiseWaveId (see
-            // WaveService)
-            newWaveId = (String) responseWaveId;
-            newWaveletId = (String) responseWaveletId;
-          }
-        }
-      }
-    }
-    OperationUtil.submitDeltas(context, waveletProvider, new SubmitRequestListener() {
-      @Override
-      public void onFailure(final String arg0) {
-        KuneWaveManagerDefault.this.onFailure("Wave creation failed, onFailure: " + arg0);
-      }
-
-      @Override
-      public void onSuccess(final int arg0, final HashedVersion arg1, final long arg2) {
-        LOG.info("Wave creation success: " + arg1);
-      }
-    });
-    LOG.info("WaveId: " + newWaveId + " waveletId: " + newWaveletId);
-    WaveRef wavename;
-    try {
-      wavename = WaveRef.of(ApiIdSerializer.instance().deserialiseWaveId(newWaveId),
-          ApiIdSerializer.instance().deserialiseWaveletId(newWaveletId));
-    } catch (final InvalidIdException e) {
-      throw new DefaultException("Error getting wave id");
-    }
-    return wavename;
-  }
-
-  @Override
-  public WaveRef createWave(@Nonnull final String title, final String message, final URL gadgetUrl,
-      @Nonnull final ParticipantId... participantsArray) {
-    return createWave(title, message, NO_WAVE_TO_COPY, gadgetUrl, participantsArray);
-  }
-
-  @Override
-  public void delParticipants(final WaveRef waveName, final String whoDel, final String... participants) {
-    final Wavelet wavelet = fetchWave(waveName, whoDel);
-    final OperationQueue opQueue = new OperationQueue();
-
-    for (final String participant : participants) {
-      final String partWithDomain = participantUtils.of(participant).toString();
-      boolean mustDel = false;
-      for (final String current : wavelet.getParticipants()) {
-        if (current.equals(partWithDomain)) {
-          mustDel = true;
-          break;
-        }
-      }
-      if (mustDel) {
-        opQueue.removeParticipantFromWavelet(wavelet, partWithDomain);
-      }
-    }
-    if (opQueue.getPendingOperations().size() > 0) {
-      doOperation(whoDel, opQueue, "add participant");
-    }
-  }
-
-  private void doOperation(final String author, final OperationQueue opQueue, final String logComment) {
-    final OperationContextImpl context = new OperationContextImpl(waveletProvider,
-        converterManager.getEventDataConverter(ProtocolVersion.DEFAULT), conversationUtil);
-    final OperationRequest request = opQueue.getPendingOperations().get(0);
-    OperationUtil.executeOperation(request, operationRegistry, context, participantUtils.of(author));
-    final String reqId = request.getId();
-    final JsonRpcResponse response = context.getResponse(reqId);
-    if (response != null && response.isError()) {
-      onFailure(context.getResponse(reqId).getErrorMessage());
-    }
-    OperationUtil.submitDeltas(context, waveletProvider, new SubmitRequestListener() {
-      @Override
-      public void onFailure(final String arg0) {
-        KuneWaveManagerDefault.this.onFailure("Wave " + logComment + " failed, onFailure: " + arg0);
-      }
-
-      @Override
-      public void onSuccess(final int arg0, final HashedVersion arg1, final long arg2) {
-        LOG.info("Wave " + logComment + " success: " + arg1);
-      }
-    });
-  }
-
-  public void doOperations(final WaveRef waveName, final String author, final OperationQueue opQueue,
-      final SubmitRequestListener listener) {
-    final OperationContextImpl context = new OperationContextImpl(waveletProvider,
-        converterManager.getEventDataConverter(ProtocolVersion.DEFAULT), conversationUtil);
-    for (final OperationRequest req : opQueue.getPendingOperations()) {
-      OperationUtil.executeOperation(req, operationRegistry, context, participantUtils.of(author));
-    }
-    OperationUtil.submitDeltas(context, waveletProvider, listener);
-  }
-
-  @Override
-  public Wavelet fetchWave(final WaveId waveId, final WaveletId waveletId, final String author) {
-    final OperationQueue opQueue = new OperationQueue();
-    opQueue.fetchWavelet(waveId, waveletId);
-    Wavelet wavelet = null;
-    final OperationContextImpl context = new OperationContextImpl(waveletProvider,
-        converterManager.getEventDataConverter(ProtocolVersion.DEFAULT), conversationUtil);
-    final OperationRequest request = opQueue.getPendingOperations().get(0);
-    OperationUtil.executeOperation(request, operationRegistry, context, participantUtils.of(author));
-    final String reqId = request.getId();
-    final JsonRpcResponse response = context.getResponse(reqId);
-    if (response != null && response.isError()) {
-      onFailure(context.getResponse(reqId).getErrorMessage());
-    } else {
-      // Duplicate code from WaveService
-      final WaveletData waveletData = (WaveletData) response.getData().get(ParamsProperty.WAVELET_DATA);
-      final Map<String, Blip> blips = new HashMap<String, Blip>();
-      final Map<String, BlipThread> threads = new HashMap<String, BlipThread>();
-      wavelet = Wavelet.deserialize(opQueue, blips, threads, waveletData);
-
-      // Deserialize threads.
-      @SuppressWarnings("unchecked")
-      final Map<String, BlipThread> tempThreads = (Map<String, BlipThread>) response.getData().get(
-          ParamsProperty.THREADS);
-      for (final Map.Entry<String, BlipThread> entry : tempThreads.entrySet()) {
-        final BlipThread thread = entry.getValue();
-        threads.put(entry.getKey(),
-            new BlipThread(thread.getId(), thread.getLocation(), thread.getBlipIds(), blips));
-      }
-
-      // Deserialize blips.
-      @SuppressWarnings("unchecked")
-      final Map<String, BlipData> blipDatas = (Map<String, BlipData>) response.getData().get(
-          ParamsProperty.BLIPS);
-      for (final Map.Entry<String, BlipData> entry : blipDatas.entrySet()) {
-        blips.put(entry.getKey(), Blip.deserialize(opQueue, wavelet, entry.getValue()));
-      }
-    }
-    return wavelet;
-  }
-
-  @Override
-  public Wavelet fetchWave(final WaveRef waveName, final String author) {
-    final WaveId waveId = waveName.getWaveId();
-    final WaveletId waveletId = waveName.getWaveletId();
-    return fetchWave(waveId, waveletId, author);
-  }
-
-  @Override
-  public boolean isParticipant(final Wavelet wavelet, final String user) {
-    return wavelet.getParticipants().contains(participantUtils.of(user).toString());
-  }
-
-  private void onFailure(final String message) {
-    final String errorMsg = TextUtils.notEmpty(message) ? message : "Wave operation failed";
-    LOG.error(errorMsg);
-    throw new DefaultException(errorMsg);
-  }
-
-  @Override
-  public String render(final Wavelet wavelet) {
-    final ClientAction clientPage = waveRenderer.render(wavelet, 0);
-    final String html = clientPage.getHtml();
-    return html;
-  }
-
-  @Override
-  public String render(final WaveRef waveRef, final String author) {
-    return render(fetchWave(waveRef, author));
-  }
-
-  @Override
-  public void setTitle(final WaveRef waveName, final String title, final String author) {
-    final Wavelet wavelet = fetchWave(waveName, author);
-    final OperationQueue opQueue = new OperationQueue();
-    opQueue.setTitleOfWavelet(wavelet, title);
-    doOperation(author, opQueue, "set title");
-  }
-
-}

Copied: trunk/src/main/java/cc/kune/wave/server/KuneWaveService.java (from rev 1523, trunk/src/main/java/cc/kune/wave/server/KuneWaveManager.java)
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/KuneWaveService.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/wave/server/KuneWaveService.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright (C) 2007-2011 The kune development team (see CREDITS for details)
+ * This file is part of kune.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package cc.kune.wave.server;
+
+import java.net.URL;
+
+import org.waveprotocol.wave.model.id.WaveId;
+import org.waveprotocol.wave.model.id.WaveletId;
+import org.waveprotocol.wave.model.wave.ParticipantId;
+import org.waveprotocol.wave.model.waveref.WaveRef;
+
+import com.google.wave.api.Wavelet;
+
+public interface KuneWaveService {
+  public static final URL WITHOUT_GADGET = null;
+
+  void addGadget(WaveRef waveName, String author, String gadgetUrl);
+
+  void addParticipants(WaveRef waveName, String author, String userWhoAdd, String... newParticipants);
+
+  WaveRef createWave(String message, ParticipantId... participants);
+
+  WaveRef createWave(String title, String message, ParticipantId... participantsArray);
+
+  WaveRef createWave(String title, String message, String waveIdToCopy, URL gadgetUrl,
+      ParticipantId... participantsArray);
+
+  WaveRef createWave(String title, String message, URL gadgetUrl, ParticipantId... participantsArray);
+
+  void delParticipants(WaveRef waveName, String whoDel, String... participants);
+
+  Wavelet fetchWave(WaveId waveId, WaveletId waveletId, String author);
+
+  Wavelet fetchWave(WaveRef waveRef, String author);
+
+  boolean isParticipant(Wavelet wavelet, String user);
+
+  String render(Wavelet wavelet);
+
+  String render(WaveRef waveRef, String author);
+
+  void setTitle(WaveRef waveName, String title, String author);
+
+}

Copied: trunk/src/main/java/cc/kune/wave/server/KuneWaveServiceDefault.java (from rev 1523, trunk/src/main/java/cc/kune/wave/server/KuneWaveManagerDefault.java)
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/KuneWaveServiceDefault.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/wave/server/KuneWaveServiceDefault.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -0,0 +1,446 @@
+/*
+ *
+ * Copyright (C) 2007-2011 The kune development team (see CREDITS for details)
+ * This file is part of kune.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package cc.kune.wave.server;
+
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.waveprotocol.box.server.CoreSettings;
+import org.waveprotocol.box.server.robots.OperationContextImpl;
+import org.waveprotocol.box.server.robots.OperationServiceRegistry;
+import org.waveprotocol.box.server.robots.util.ConversationUtil;
+import org.waveprotocol.box.server.robots.util.OperationUtil;
+import org.waveprotocol.box.server.waveserver.WaveletProvider;
+import org.waveprotocol.box.server.waveserver.WaveletProvider.SubmitRequestListener;
+import org.waveprotocol.wave.model.id.InvalidIdException;
+import org.waveprotocol.wave.model.id.WaveId;
+import org.waveprotocol.wave.model.id.WaveletId;
+import org.waveprotocol.wave.model.version.HashedVersion;
+import org.waveprotocol.wave.model.wave.ParticipantId;
+import org.waveprotocol.wave.model.waveref.WaveRef;
+
+import cc.kune.common.client.utils.TextUtils;
+import cc.kune.core.client.errors.DefaultException;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import com.google.wave.api.Annotation;
+import com.google.wave.api.ApiIdSerializer;
+import com.google.wave.api.Blip;
+import com.google.wave.api.BlipContent;
+import com.google.wave.api.BlipData;
+import com.google.wave.api.BlipThread;
+import com.google.wave.api.Element;
+import com.google.wave.api.ElementType;
+import com.google.wave.api.FormElement;
+import com.google.wave.api.Gadget;
+import com.google.wave.api.Image;
+import com.google.wave.api.JsonRpcConstant.ParamsProperty;
+import com.google.wave.api.JsonRpcResponse;
+import com.google.wave.api.Line;
+import com.google.wave.api.OperationQueue;
+import com.google.wave.api.OperationRequest;
+import com.google.wave.api.OperationRequest.Parameter;
+import com.google.wave.api.ProtocolVersion;
+import com.google.wave.api.Range;
+import com.google.wave.api.Wavelet;
+import com.google.wave.api.data.converter.EventDataConverterManager;
+import com.google.wave.api.impl.DocumentModifyAction;
+import com.google.wave.api.impl.DocumentModifyAction.BundledAnnotation;
+import com.google.wave.api.impl.DocumentModifyAction.ModifyHow;
+import com.google.wave.api.impl.WaveletData;
+import com.google.wave.splash.rpc.ClientAction;
+import com.google.wave.splash.web.template.WaveRenderer;
+
+public class KuneWaveServiceDefault implements KuneWaveService {
+  public static final Log LOG = LogFactory.getLog(KuneWaveServiceDefault.class);
+
+  // See: DocumentModifyServiceTest
+  private static final String NO_ANNOTATION_KEY = null;
+  private static final List<BundledAnnotation> NO_BUNDLED_ANNOTATIONS = Collections.emptyList();
+  private static final String NO_TITLE = "";
+  private static final List<String> NO_VALUES = Collections.<String> emptyList();
+  private static final String NO_WAVE_TO_COPY = null;
+
+  /**
+   * 
+   * Copy blips
+   * 
+   * @param fromBlip
+   * @param toBlip
+   * 
+   * @author yurize at apache.org (Yuri Zelikov)
+   * 
+   */
+  public static void copyWavelet(final Blip fromBlip, final Blip toBlip) {
+    for (final BlipContent blipContent : fromBlip.all().values()) {
+      toBlip.append(blipContent);
+    }
+    // Deep copy annotations
+    for (final Annotation annotation : fromBlip.getAnnotations()) {
+      final Range range = annotation.getRange();
+      try {
+        toBlip.range(range.getStart() + 1, range.getEnd() + 1).annotate(annotation.getName(),
+            annotation.getValue());
+      } catch (final IndexOutOfBoundsException e) {
+        // Don't copy faulty annotations
+      }
+    }
+  }
+
+  public static void copyWaveletElements(final Blip fromBlip, final Blip toBlip) {
+    // Deep copy form elements.
+    // DocumentModifyService don't permit this:
+    // "Can't insert other elements than text and gadgets at the moment");
+    for (final Entry<Integer, Element> entry : fromBlip.getElements().entrySet()) {
+      final ElementType type = entry.getValue().getType();
+      Element result = null;
+      if (FormElement.getFormElementTypes().contains(type)) {
+        result = new FormElement(type, entry.getValue().getProperties());
+      } else if (type == ElementType.GADGET) {
+        result = new Gadget(entry.getValue().getProperties());
+      } else if (type == ElementType.IMAGE) {
+        result = new Image(entry.getValue().getProperties());
+      } else if (type == ElementType.LINE) {
+        result = new Line(entry.getValue().getProperties());
+      } else {
+        result = new Element(type, entry.getValue().getProperties());
+      }
+      toBlip.append(result);
+    }
+  }
+
+  private final ConversationUtil conversationUtil;
+  private final EventDataConverterManager converterManager;
+  private final String domain;
+  private final OperationServiceRegistry operationRegistry;
+  private final ParticipantUtils participantUtils;
+  private final WaveletProvider waveletProvider;
+  private final WaveRenderer waveRenderer;
+
+  @Inject
+  public KuneWaveServiceDefault(final EventDataConverterManager converterManager,
+      @Named("DataApiRegistry") final OperationServiceRegistry operationRegistry,
+      final WaveletProvider waveletProvider, final ConversationUtil conversationUtil,
+      final ParticipantUtils participantUtils, final WaveRenderer waveRenderer,
+      @Named(CoreSettings.WAVE_SERVER_DOMAIN) final String domain) {
+    this.converterManager = converterManager;
+    this.waveletProvider = waveletProvider;
+    this.conversationUtil = conversationUtil;
+    this.operationRegistry = operationRegistry;
+    this.participantUtils = participantUtils;
+    this.waveRenderer = waveRenderer;
+    this.domain = domain;
+  }
+
+  @Override
+  public void addGadget(final WaveRef waveName, final String author, final String gadgetUrl) {
+    // See DocumentModifyServiceTest
+    final List<Element> elementsIn = Lists.newArrayListWithCapacity(1);
+    final Map<String, String> properties = Maps.newHashMap();
+    properties.put(Gadget.URL, gadgetUrl);
+    properties.put(Gadget.AUTHOR, participantUtils.of(author).getAddress());
+    final Gadget gadget = new Gadget(properties);
+
+    elementsIn.add(gadget);
+    final Wavelet wavelet = fetchWave(waveName, author);
+    final OperationQueue opQueue = new OperationQueue();
+    final Blip rootBlip = wavelet.getRootBlip();
+
+    opQueue.modifyDocument(rootBlip).addParameter(
+        Parameter.of(ParamsProperty.MODIFY_ACTION, new DocumentModifyAction(ModifyHow.INSERT, NO_VALUES,
+            NO_ANNOTATION_KEY, elementsIn, NO_BUNDLED_ANNOTATIONS, false)));
+    opQueue.modifyDocument(rootBlip).addParameter(Parameter.of(ParamsProperty.INDEX, 1));
+    doOperation(author, opQueue, "add gadget");
+  }
+
+  @Override
+  public void addParticipants(final WaveRef waveName, final String author, final String userWhoAdds,
+      final String... newLocalParticipants) {
+    final Wavelet wavelet = fetchWave(waveName, author);
+    final OperationQueue opQueue = new OperationQueue();
+
+    for (final String newLocalParticipant : newLocalParticipants) {
+      final String newPartWithDomain = participantUtils.of(newLocalParticipant).toString();
+      boolean mustAdd = true;
+      for (final String current : wavelet.getParticipants()) {
+        if (current.equals(newPartWithDomain)) {
+          // Current user is a participant already (issue #73)
+          mustAdd = false;
+          break;
+        }
+      }
+      if (mustAdd) {
+        opQueue.addParticipantToWavelet(wavelet, newPartWithDomain);
+      }
+    }
+    if (opQueue.getPendingOperations().size() > 0) {
+      final String whoAdd = wavelet.getParticipants().contains(participantUtils.of(userWhoAdds)) ? userWhoAdds
+          : author;
+      doOperation(whoAdd, opQueue, "add participant");
+    }
+  }
+
+  @Override
+  public WaveRef createWave(final String message, final ParticipantId... participants) {
+    return createWave(NO_TITLE, message, participants);
+  }
+
+  @Override
+  public WaveRef createWave(@Nonnull final String title, final String message,
+      @Nonnull final ParticipantId... participantsArray) {
+    return createWave(title, message, WITHOUT_GADGET, participantsArray);
+  }
+
+  @Override
+  public WaveRef createWave(@Nonnull final String title, final String message,
+      final String waveIdToCopy, final URL gadgetUrl, @Nonnull final ParticipantId... participantsArray) {
+    String newWaveId = null;
+    String newWaveletId = null;
+    final Set<String> participants = new HashSet<String>();
+    for (final ParticipantId participant : participantsArray) {
+      participants.add(participant.toString());
+    }
+    final ParticipantId user = participantsArray[0];
+    final OperationQueue opQueue = new OperationQueue();
+    final Wavelet newWavelet = opQueue.createWavelet(domain, participants);
+    opQueue.setTitleOfWavelet(newWavelet, title);
+    final Blip rootBlip = newWavelet.getRootBlip();
+    rootBlip.append(new com.google.wave.api.Markup(message).getText());
+
+    if (waveIdToCopy != NO_WAVE_TO_COPY) {
+      try {
+        WaveId copyWaveId;
+        copyWaveId = WaveId.ofChecked(domain, waveIdToCopy);
+        final Wavelet waveletToCopy = fetchWave(copyWaveId, WaveletId.of(domain, "conv+root"),
+            participantsArray[0].toString());
+        if (waveletToCopy != null) {
+          copyWavelet(waveletToCopy.getRootBlip(), rootBlip);
+        }
+      } catch (final InvalidIdException e) {
+        LOG.error("Error copying wave content", e);
+      } catch (final DefaultException e2) {
+        LOG.error("Error copying wave content", e2);
+      }
+    }
+
+    if (gadgetUrl != WITHOUT_GADGET) {
+      final Gadget gadget = new Gadget(gadgetUrl.toString());
+      rootBlip.append(gadget);
+    }
+
+    final OperationContextImpl context = new OperationContextImpl(waveletProvider,
+        converterManager.getEventDataConverter(ProtocolVersion.DEFAULT), conversationUtil);
+    for (final OperationRequest req : opQueue.getPendingOperations()) {
+      OperationUtil.executeOperation(req, operationRegistry, context, user);
+      final String reqId = req.getId();
+      final JsonRpcResponse response = context.getResponse(reqId);
+      if (response != null) {
+        if (response.isError()) {
+          onFailure(context.getResponse(reqId).getErrorMessage());
+        } else {
+          final Object responseWaveId = response.getData().get(ParamsProperty.WAVE_ID);
+          final Object responseWaveletId = response.getData().get(ParamsProperty.WAVELET_ID);
+          if (responseWaveId != null && responseWaveletId != null) {
+            // This is serialized use
+            // ApiIdSerializer.instance().deserialiseWaveId (see
+            // WaveService)
+            newWaveId = (String) responseWaveId;
+            newWaveletId = (String) responseWaveletId;
+          }
+        }
+      }
+    }
+    OperationUtil.submitDeltas(context, waveletProvider, new SubmitRequestListener() {
+      @Override
+      public void onFailure(final String arg0) {
+        KuneWaveServiceDefault.this.onFailure("Wave creation failed, onFailure: " + arg0);
+      }
+
+      @Override
+      public void onSuccess(final int arg0, final HashedVersion arg1, final long arg2) {
+        LOG.info("Wave creation success: " + arg1);
+      }
+    });
+    LOG.info("WaveId: " + newWaveId + " waveletId: " + newWaveletId);
+    WaveRef wavename;
+    try {
+      wavename = WaveRef.of(ApiIdSerializer.instance().deserialiseWaveId(newWaveId),
+          ApiIdSerializer.instance().deserialiseWaveletId(newWaveletId));
+    } catch (final InvalidIdException e) {
+      throw new DefaultException("Error getting wave id");
+    }
+    return wavename;
+  }
+
+  @Override
+  public WaveRef createWave(@Nonnull final String title, final String message, final URL gadgetUrl,
+      @Nonnull final ParticipantId... participantsArray) {
+    return createWave(title, message, NO_WAVE_TO_COPY, gadgetUrl, participantsArray);
+  }
+
+  @Override
+  public void delParticipants(final WaveRef waveName, final String whoDel, final String... participants) {
+    final Wavelet wavelet = fetchWave(waveName, whoDel);
+    final OperationQueue opQueue = new OperationQueue();
+
+    for (final String participant : participants) {
+      final String partWithDomain = participantUtils.of(participant).toString();
+      boolean mustDel = false;
+      for (final String current : wavelet.getParticipants()) {
+        if (current.equals(partWithDomain)) {
+          mustDel = true;
+          break;
+        }
+      }
+      if (mustDel) {
+        opQueue.removeParticipantFromWavelet(wavelet, partWithDomain);
+      }
+    }
+    if (opQueue.getPendingOperations().size() > 0) {
+      doOperation(whoDel, opQueue, "add participant");
+    }
+  }
+
+  private void doOperation(final String author, final OperationQueue opQueue, final String logComment) {
+    final OperationContextImpl context = new OperationContextImpl(waveletProvider,
+        converterManager.getEventDataConverter(ProtocolVersion.DEFAULT), conversationUtil);
+    final OperationRequest request = opQueue.getPendingOperations().get(0);
+    OperationUtil.executeOperation(request, operationRegistry, context, participantUtils.of(author));
+    final String reqId = request.getId();
+    final JsonRpcResponse response = context.getResponse(reqId);
+    if (response != null && response.isError()) {
+      onFailure(context.getResponse(reqId).getErrorMessage());
+    }
+    OperationUtil.submitDeltas(context, waveletProvider, new SubmitRequestListener() {
+      @Override
+      public void onFailure(final String arg0) {
+        KuneWaveServiceDefault.this.onFailure("Wave " + logComment + " failed, onFailure: " + arg0);
+      }
+
+      @Override
+      public void onSuccess(final int arg0, final HashedVersion arg1, final long arg2) {
+        LOG.info("Wave " + logComment + " success: " + arg1);
+      }
+    });
+  }
+
+  public void doOperations(final WaveRef waveName, final String author, final OperationQueue opQueue,
+      final SubmitRequestListener listener) {
+    final OperationContextImpl context = new OperationContextImpl(waveletProvider,
+        converterManager.getEventDataConverter(ProtocolVersion.DEFAULT), conversationUtil);
+    for (final OperationRequest req : opQueue.getPendingOperations()) {
+      OperationUtil.executeOperation(req, operationRegistry, context, participantUtils.of(author));
+    }
+    OperationUtil.submitDeltas(context, waveletProvider, listener);
+  }
+
+  @Override
+  public Wavelet fetchWave(final WaveId waveId, final WaveletId waveletId, final String author) {
+    final OperationQueue opQueue = new OperationQueue();
+    opQueue.fetchWavelet(waveId, waveletId);
+    Wavelet wavelet = null;
+    final OperationContextImpl context = new OperationContextImpl(waveletProvider,
+        converterManager.getEventDataConverter(ProtocolVersion.DEFAULT), conversationUtil);
+    final OperationRequest request = opQueue.getPendingOperations().get(0);
+    OperationUtil.executeOperation(request, operationRegistry, context, participantUtils.of(author));
+    final String reqId = request.getId();
+    final JsonRpcResponse response = context.getResponse(reqId);
+    if (response != null && response.isError()) {
+      onFailure(context.getResponse(reqId).getErrorMessage());
+    } else {
+      // Duplicate code from WaveService
+      final WaveletData waveletData = (WaveletData) response.getData().get(ParamsProperty.WAVELET_DATA);
+      final Map<String, Blip> blips = new HashMap<String, Blip>();
+      final Map<String, BlipThread> threads = new HashMap<String, BlipThread>();
+      wavelet = Wavelet.deserialize(opQueue, blips, threads, waveletData);
+
+      // Deserialize threads.
+      @SuppressWarnings("unchecked")
+      final Map<String, BlipThread> tempThreads = (Map<String, BlipThread>) response.getData().get(
+          ParamsProperty.THREADS);
+      for (final Map.Entry<String, BlipThread> entry : tempThreads.entrySet()) {
+        final BlipThread thread = entry.getValue();
+        threads.put(entry.getKey(),
+            new BlipThread(thread.getId(), thread.getLocation(), thread.getBlipIds(), blips));
+      }
+
+      // Deserialize blips.
+      @SuppressWarnings("unchecked")
+      final Map<String, BlipData> blipDatas = (Map<String, BlipData>) response.getData().get(
+          ParamsProperty.BLIPS);
+      for (final Map.Entry<String, BlipData> entry : blipDatas.entrySet()) {
+        blips.put(entry.getKey(), Blip.deserialize(opQueue, wavelet, entry.getValue()));
+      }
+    }
+    return wavelet;
+  }
+
+  @Override
+  public Wavelet fetchWave(final WaveRef waveName, final String author) {
+    final WaveId waveId = waveName.getWaveId();
+    final WaveletId waveletId = waveName.getWaveletId();
+    return fetchWave(waveId, waveletId, author);
+  }
+
+  @Override
+  public boolean isParticipant(final Wavelet wavelet, final String user) {
+    return wavelet.getParticipants().contains(participantUtils.of(user).toString());
+  }
+
+  private void onFailure(final String message) {
+    final String errorMsg = TextUtils.notEmpty(message) ? message : "Wave operation failed";
+    LOG.error(errorMsg);
+    throw new DefaultException(errorMsg);
+  }
+
+  @Override
+  public String render(final Wavelet wavelet) {
+    final ClientAction clientPage = waveRenderer.render(wavelet, 0);
+    final String html = clientPage.getHtml();
+    return html;
+  }
+
+  @Override
+  public String render(final WaveRef waveRef, final String author) {
+    return render(fetchWave(waveRef, author));
+  }
+
+  @Override
+  public void setTitle(final WaveRef waveName, final String title, final String author) {
+    final Wavelet wavelet = fetchWave(waveName, author);
+    final OperationQueue opQueue = new OperationQueue();
+    opQueue.setTitleOfWavelet(wavelet, title);
+    doOperation(author, opQueue, "set title");
+  }
+
+}

Deleted: trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -1,18 +0,0 @@
-package cc.kune.wave.server;
-
-import org.waveprotocol.wave.model.waveref.InvalidWaveRefException;
-import org.waveprotocol.wave.model.waveref.WaveRef;
-import org.waveprotocol.wave.util.escapers.jvm.JavaWaverefEncoder;
-
-import cc.kune.core.client.errors.DefaultException;
-import cc.kune.domain.Content;
-
-public class KuneWaveUtils {
-  public static WaveRef getWaveRef(final Content content) {
-    try {
-      return JavaWaverefEncoder.decodeWaveRefFromPath(String.valueOf(content.getWaveId()));
-    } catch (final InvalidWaveRefException e) {
-      throw new DefaultException("Error getting the wave");
-    }
-  }
-}

Added: trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -0,0 +1,22 @@
+package cc.kune.wave.server;
+
+import org.waveprotocol.wave.model.waveref.InvalidWaveRefException;
+import org.waveprotocol.wave.model.waveref.WaveRef;
+import org.waveprotocol.wave.util.escapers.jvm.JavaWaverefEncoder;
+
+import cc.kune.core.client.errors.DefaultException;
+import cc.kune.domain.Content;
+
+public class KuneWaveUtils {
+  public static String getUrl(final WaveRef waveref) {
+    return JavaWaverefEncoder.encodeToUriPathSegment(waveref);
+  }
+
+  public static WaveRef getWaveRef(final Content content) {
+    try {
+      return JavaWaverefEncoder.decodeWaveRefFromPath(String.valueOf(content.getWaveId()));
+    } catch (final InvalidWaveRefException e) {
+      throw new DefaultException("Error getting the wave");
+    }
+  }
+}

Modified: trunk/src/main/java/cc/kune/wave/server/ParticipantUtils.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/ParticipantUtils.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/java/cc/kune/wave/server/ParticipantUtils.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -19,12 +19,16 @@
  */
 package cc.kune.wave.server;
 
+import java.util.Iterator;
+import java.util.Set;
+
 import org.waveprotocol.box.server.CoreSettings;
 import org.waveprotocol.wave.model.wave.InvalidParticipantAddress;
 import org.waveprotocol.wave.model.wave.ParticipantId;
 
 import cc.kune.core.client.errors.DefaultException;
 import cc.kune.core.server.properties.KuneBasicProperties;
+import cc.kune.domain.Group;
 
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
@@ -33,33 +37,42 @@
 @Singleton
 public class ParticipantUtils {
 
-    private final String domain;
-    private final ParticipantId superAdmin;
+  private final String domain;
+  private final ParticipantId superAdmin;
 
-    @Inject
-    public ParticipantUtils(@Named(CoreSettings.WAVE_SERVER_DOMAIN) final String domain,
-            final KuneBasicProperties databaseProperties) throws InvalidParticipantAddress {
-        this.domain = domain;
-        superAdmin = ofImpl(databaseProperties.getAdminShortName());
-    }
+  @Inject
+  public ParticipantUtils(@Named(CoreSettings.WAVE_SERVER_DOMAIN) final String domain,
+      final KuneBasicProperties databaseProperties) throws InvalidParticipantAddress {
+    this.domain = domain;
+    superAdmin = ofImpl(databaseProperties.getAdminShortName());
+  }
 
-    public ParticipantId getSuperAdmin() {
-        return superAdmin;
-    }
+  public ParticipantId getSuperAdmin() {
+    return superAdmin;
+  }
 
-    public ParticipantId of(final String username) {
-        return ofImpl(username);
+  public ParticipantId[] listFrom(final Set<Group> list) {
+    final ParticipantId[] array = new ParticipantId[list.size()];
+    final Iterator<Group> iterator = list.iterator();
+    for (int i = 0; i < list.size(); i++) {
+      array[i] = of(iterator.next().getShortName());
     }
+    return array;
+  }
 
-    private ParticipantId ofImpl(final String username) {
-        try {
-            if (username.contains(ParticipantId.DOMAIN_PREFIX)) {
-                return ParticipantId.of(username);
-            } else {
-                return ParticipantId.of(username + ParticipantId.DOMAIN_PREFIX + domain);
-            }
-        } catch (final InvalidParticipantAddress e) {
-            throw new DefaultException("Error getting Wave participant Id");
-        }
+  public ParticipantId of(final String username) {
+    return ofImpl(username);
+  }
+
+  private ParticipantId ofImpl(final String username) {
+    try {
+      if (username.contains(ParticipantId.DOMAIN_PREFIX)) {
+        return ParticipantId.of(username);
+      } else {
+        return ParticipantId.of(username + ParticipantId.DOMAIN_PREFIX + domain);
+      }
+    } catch (final InvalidParticipantAddress e) {
+      throw new DefaultException("Error getting Wave participant Id");
     }
+  }
 }

Modified: trunk/src/main/resources/kune.properties
===================================================================
--- trunk/src/main/resources/kune.properties	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/main/resources/kune.properties	2011-09-20 14:28:24 UTC (rev 1524)
@@ -29,7 +29,7 @@
 kune.chat.domain = localhost
 kune.chat.roomHost = rooms.localhost
 
-### Feedback syste
+### Feedback system
 kune.feedback.enabled = true
 # List of participants to give feedback, comma-separated
 kune.feedback.to = admin
@@ -98,7 +98,8 @@
 kune.upload.location = /var/lib/kune/uploads/
 kune.upload.maxfilesizeinmegas = 10
 kune.upload.maxfilesizeinks = 10000000
-kune.upload.delayfortest = 50
+# to test in development phase, you can use values as 50
+kune.upload.delayfortest = 0
 
 ### Gallery options
 kune.upload.gallerypermittedextensions = jpg,jpeg,png,gif,bmp,svg,avi,mpg,mpeg,ogg,mov,tif,tiff,mp3,wav

Deleted: trunk/src/test/java/cc/kune/wave/server/KuneWaveManagerDefaultTest.java
===================================================================
--- trunk/src/test/java/cc/kune/wave/server/KuneWaveManagerDefaultTest.java	2011-09-20 01:32:58 UTC (rev 1523)
+++ trunk/src/test/java/cc/kune/wave/server/KuneWaveManagerDefaultTest.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -1,189 +0,0 @@
-/*
- *
- * Copyright (C) 2007-2011 The kune development team (see CREDITS for details)
- * This file is part of kune.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package cc.kune.wave.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-import java.net.URL;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.waveprotocol.wave.model.waveref.WaveRef;
-
-import cc.kune.core.client.errors.DefaultException;
-import cc.kune.core.server.integration.IntegrationTest;
-import cc.kune.core.server.integration.IntegrationTestHelper;
-
-import com.google.inject.Inject;
-import com.google.wave.api.Wavelet;
-
-public class KuneWaveManagerDefaultTest extends IntegrationTest {
-
-  private static final String MESSAGE = "testing";
-  private static final String NEW_PARTICIPANT = "newparti";
-  private static final String RICHTEXT_MESSAGE = "<b>" + MESSAGE + "</b>";
-  private static final String TEST_GADGET = "http://wave-api.appspot.com/public/gadgets/areyouin/gadget.xml";
-  private static final String TITLE = "title";
-  private static final String TITLENEW = "titleNew";
-  @Inject
-  KuneWaveManager manager;
-  @Inject
-  ParticipantUtils participantUtils;
-
-  @Test
-  public void addAndRemoveParticipant() throws IOException {
-    doLogin();
-    final String whoDels = getSiteAdminShortName();
-    final WaveRef waveletName = createTestWave();
-    assertNotNull(waveletName);
-    manager.addParticipants(waveletName, getSiteAdminShortName(), whoDels, NEW_PARTICIPANT);
-    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
-    assertNotNull(fetchWavelet);
-    assertEquals(2, fetchWavelet.getParticipants().size());
-    assertTrue(manager.isParticipant(fetchWavelet, NEW_PARTICIPANT));
-    assertTrue(manager.isParticipant(fetchWavelet, getSiteAdminShortName()));
-    manager.delParticipants(waveletName, whoDels, NEW_PARTICIPANT);
-    final Wavelet fetchDelWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
-    assertNotNull(fetchDelWavelet);
-    assertEquals(1, fetchDelWavelet.getParticipants().size());
-    assertTrue(manager.isParticipant(fetchDelWavelet, getSiteAdminShortName()));
-    assertFalse(manager.isParticipant(fetchDelWavelet, NEW_PARTICIPANT));
-    manager.addParticipants(waveletName, getSiteAdminShortName(), whoDels, NEW_PARTICIPANT);
-    // Del all
-    manager.delParticipants(waveletName, whoDels, getSiteAdminShortName(), NEW_PARTICIPANT);
-  }
-
-  @Test
-  public void addGadget() throws DefaultException, IOException {
-    doLogin();
-    final WaveRef waveletName = createTestWave();
-    assertNotNull(waveletName);
-    manager.addGadget(waveletName, getSiteAdminShortName(), TEST_GADGET);
-  }
-
-  private void addParticipant(final String whoAdds) throws IOException {
-    doLogin();
-    final WaveRef waveletName = createTestWave();
-    assertNotNull(waveletName);
-    manager.addParticipants(waveletName, getSiteAdminShortName(), whoAdds, NEW_PARTICIPANT);
-    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
-    assertNotNull(fetchWavelet);
-    assertEquals(2, fetchWavelet.getParticipants().size());
-    assertTrue(manager.isParticipant(fetchWavelet, NEW_PARTICIPANT));
-    assertTrue(manager.isParticipant(fetchWavelet, getSiteAdminShortName()));
-  }
-
-  @Test
-  public void addParticipantTwice() throws IOException {
-    doLogin();
-    final WaveRef waveletName = createTestWave();
-    assertNotNull(waveletName);
-    manager.addParticipants(waveletName, getSiteAdminShortName(), getSiteAdminShortName(),
-        NEW_PARTICIPANT);
-    manager.addParticipants(waveletName, getSiteAdminShortName(), getSiteAdminShortName(),
-        NEW_PARTICIPANT, NEW_PARTICIPANT);
-    manager.addParticipants(waveletName, getSiteAdminShortName(), getSiteAdminShortName(),
-        NEW_PARTICIPANT, NEW_PARTICIPANT, NEW_PARTICIPANT);
-    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
-    assertNotNull(fetchWavelet);
-    assertEquals(2, fetchWavelet.getParticipants().size());
-    assertTrue(manager.isParticipant(fetchWavelet, NEW_PARTICIPANT));
-    assertTrue(manager.isParticipant(fetchWavelet, getSiteAdminShortName()));
-  }
-
-  @Test
-  public void authorAddParticipant() throws DefaultException, IOException {
-    final String whoAdds = getSiteAdminShortName();
-    addParticipant(whoAdds);
-  }
-
-  @Before
-  public void before() {
-    new IntegrationTestHelper(this);
-  }
-
-  private WaveRef createTestWave() {
-    return manager.createWave(TITLE, RICHTEXT_MESSAGE, participantUtils.of(getSiteAdminShortName()));
-  }
-
-  @Test
-  public void createWave() throws DefaultException, IOException {
-    doLogin();
-    final WaveRef waveletName = manager.createWave(RICHTEXT_MESSAGE,
-        participantUtils.of(getSiteAdminShortName()));
-    assertNotNull(waveletName);
-    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
-    assertNotNull(fetchWavelet);
-    assertTrue(fetchWavelet.getRootBlip().getAnnotations().size() > 0);
-    assertTrue(fetchWavelet.getRootBlip().getContent().contains(MESSAGE));
-  }
-
-  @Test
-  public void createWaveWithGadget() throws DefaultException, IOException {
-    doLogin();
-    final WaveRef waveletName = manager.createWave(TITLE, RICHTEXT_MESSAGE, new URL(TEST_GADGET),
-        participantUtils.of(getSiteAdminShortName()));
-    assertNotNull(waveletName);
-    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
-    assertNotNull(fetchWavelet);
-    assertTrue(fetchWavelet.getRootBlip().getContent().contains(MESSAGE));
-  }
-
-  @Test
-  public void createWaveWithTitle() throws DefaultException, IOException {
-    doLogin();
-    final WaveRef waveletName = createTestWave();
-    assertNotNull(waveletName);
-    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
-    assertNotNull(fetchWavelet);
-    assertTrue(fetchWavelet.getRootBlip().getContent().contains(MESSAGE));
-    assertEquals(TITLE, fetchWavelet.getTitle());
-  }
-
-  @Test
-  public void otherMemberAddParticipant() throws DefaultException, IOException {
-    final String whoAdds = "otherMember";
-    addParticipant(whoAdds);
-  }
-
-  @Test
-  public void renderWave() throws DefaultException, IOException {
-    doLogin();
-    final WaveRef waveletName = createTestWave();
-    assertNotNull(manager.render(waveletName, getSiteAdminShortName()));
-  }
-
-  @Test
-  public void setTitle() throws DefaultException, IOException {
-    doLogin();
-    final WaveRef waveletName = createTestWave();
-    assertNotNull(waveletName);
-    manager.setTitle(waveletName, TITLENEW, getSiteAdminShortName());
-    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
-    assertNotNull(fetchWavelet);
-    assertTrue(fetchWavelet.getRootBlip().getContent().contains(MESSAGE));
-    assertEquals(TITLENEW, fetchWavelet.getTitle());
-  }
-
-}

Copied: trunk/src/test/java/cc/kune/wave/server/KuneWaveServiceDefaultTest.java (from rev 1511, trunk/src/test/java/cc/kune/wave/server/KuneWaveManagerDefaultTest.java)
===================================================================
--- trunk/src/test/java/cc/kune/wave/server/KuneWaveServiceDefaultTest.java	                        (rev 0)
+++ trunk/src/test/java/cc/kune/wave/server/KuneWaveServiceDefaultTest.java	2011-09-20 14:28:24 UTC (rev 1524)
@@ -0,0 +1,189 @@
+/*
+ *
+ * Copyright (C) 2007-2011 The kune development team (see CREDITS for details)
+ * This file is part of kune.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package cc.kune.wave.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.waveprotocol.wave.model.waveref.WaveRef;
+
+import cc.kune.core.client.errors.DefaultException;
+import cc.kune.core.server.integration.IntegrationTest;
+import cc.kune.core.server.integration.IntegrationTestHelper;
+
+import com.google.inject.Inject;
+import com.google.wave.api.Wavelet;
+
+public class KuneWaveServiceDefaultTest extends IntegrationTest {
+
+  private static final String MESSAGE = "testing";
+  private static final String NEW_PARTICIPANT = "newparti";
+  private static final String RICHTEXT_MESSAGE = "<b>" + MESSAGE + "</b>";
+  private static final String TEST_GADGET = "http://wave-api.appspot.com/public/gadgets/areyouin/gadget.xml";
+  private static final String TITLE = "title";
+  private static final String TITLENEW = "titleNew";
+  @Inject
+  KuneWaveService manager;
+  @Inject
+  ParticipantUtils participantUtils;
+
+  @Test
+  public void addAndRemoveParticipant() throws IOException {
+    doLogin();
+    final String whoDels = getSiteAdminShortName();
+    final WaveRef waveletName = createTestWave();
+    assertNotNull(waveletName);
+    manager.addParticipants(waveletName, getSiteAdminShortName(), whoDels, NEW_PARTICIPANT);
+    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
+    assertNotNull(fetchWavelet);
+    assertEquals(2, fetchWavelet.getParticipants().size());
+    assertTrue(manager.isParticipant(fetchWavelet, NEW_PARTICIPANT));
+    assertTrue(manager.isParticipant(fetchWavelet, getSiteAdminShortName()));
+    manager.delParticipants(waveletName, whoDels, NEW_PARTICIPANT);
+    final Wavelet fetchDelWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
+    assertNotNull(fetchDelWavelet);
+    assertEquals(1, fetchDelWavelet.getParticipants().size());
+    assertTrue(manager.isParticipant(fetchDelWavelet, getSiteAdminShortName()));
+    assertFalse(manager.isParticipant(fetchDelWavelet, NEW_PARTICIPANT));
+    manager.addParticipants(waveletName, getSiteAdminShortName(), whoDels, NEW_PARTICIPANT);
+    // Del all
+    manager.delParticipants(waveletName, whoDels, getSiteAdminShortName(), NEW_PARTICIPANT);
+  }
+
+  @Test
+  public void addGadget() throws DefaultException, IOException {
+    doLogin();
+    final WaveRef waveletName = createTestWave();
+    assertNotNull(waveletName);
+    manager.addGadget(waveletName, getSiteAdminShortName(), TEST_GADGET);
+  }
+
+  private void addParticipant(final String whoAdds) throws IOException {
+    doLogin();
+    final WaveRef waveletName = createTestWave();
+    assertNotNull(waveletName);
+    manager.addParticipants(waveletName, getSiteAdminShortName(), whoAdds, NEW_PARTICIPANT);
+    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
+    assertNotNull(fetchWavelet);
+    assertEquals(2, fetchWavelet.getParticipants().size());
+    assertTrue(manager.isParticipant(fetchWavelet, NEW_PARTICIPANT));
+    assertTrue(manager.isParticipant(fetchWavelet, getSiteAdminShortName()));
+  }
+
+  @Test
+  public void addParticipantTwice() throws IOException {
+    doLogin();
+    final WaveRef waveletName = createTestWave();
+    assertNotNull(waveletName);
+    manager.addParticipants(waveletName, getSiteAdminShortName(), getSiteAdminShortName(),
+        NEW_PARTICIPANT);
+    manager.addParticipants(waveletName, getSiteAdminShortName(), getSiteAdminShortName(),
+        NEW_PARTICIPANT, NEW_PARTICIPANT);
+    manager.addParticipants(waveletName, getSiteAdminShortName(), getSiteAdminShortName(),
+        NEW_PARTICIPANT, NEW_PARTICIPANT, NEW_PARTICIPANT);
+    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
+    assertNotNull(fetchWavelet);
+    assertEquals(2, fetchWavelet.getParticipants().size());
+    assertTrue(manager.isParticipant(fetchWavelet, NEW_PARTICIPANT));
+    assertTrue(manager.isParticipant(fetchWavelet, getSiteAdminShortName()));
+  }
+
+  @Test
+  public void authorAddParticipant() throws DefaultException, IOException {
+    final String whoAdds = getSiteAdminShortName();
+    addParticipant(whoAdds);
+  }
+
+  @Before
+  public void before() {
+    new IntegrationTestHelper(this);
+  }
+
+  private WaveRef createTestWave() {
+    return manager.createWave(TITLE, RICHTEXT_MESSAGE, participantUtils.of(getSiteAdminShortName()));
+  }
+
+  @Test
+  public void createWave() throws DefaultException, IOException {
+    doLogin();
+    final WaveRef waveletName = manager.createWave(RICHTEXT_MESSAGE,
+        participantUtils.of(getSiteAdminShortName()));
+    assertNotNull(waveletName);
+    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
+    assertNotNull(fetchWavelet);
+    assertTrue(fetchWavelet.getRootBlip().getAnnotations().size() > 0);
+    assertTrue(fetchWavelet.getRootBlip().getContent().contains(MESSAGE));
+  }
+
+  @Test
+  public void createWaveWithGadget() throws DefaultException, IOException {
+    doLogin();
+    final WaveRef waveletName = manager.createWave(TITLE, RICHTEXT_MESSAGE, new URL(TEST_GADGET),
+        participantUtils.of(getSiteAdminShortName()));
+    assertNotNull(waveletName);
+    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
+    assertNotNull(fetchWavelet);
+    assertTrue(fetchWavelet.getRootBlip().getContent().contains(MESSAGE));
+  }
+
+  @Test
+  public void createWaveWithTitle() throws DefaultException, IOException {
+    doLogin();
+    final WaveRef waveletName = createTestWave();
+    assertNotNull(waveletName);
+    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
+    assertNotNull(fetchWavelet);
+    assertTrue(fetchWavelet.getRootBlip().getContent().contains(MESSAGE));
+    assertEquals(TITLE, fetchWavelet.getTitle());
+  }
+
+  @Test
+  public void otherMemberAddParticipant() throws DefaultException, IOException {
+    final String whoAdds = "otherMember";
+    addParticipant(whoAdds);
+  }
+
+  @Test
+  public void renderWave() throws DefaultException, IOException {
+    doLogin();
+    final WaveRef waveletName = createTestWave();
+    assertNotNull(manager.render(waveletName, getSiteAdminShortName()));
+  }
+
+  @Test
+  public void setTitle() throws DefaultException, IOException {
+    doLogin();
+    final WaveRef waveletName = createTestWave();
+    assertNotNull(waveletName);
+    manager.setTitle(waveletName, TITLENEW, getSiteAdminShortName());
+    final Wavelet fetchWavelet = manager.fetchWave(waveletName, getSiteAdminShortName());
+    assertNotNull(fetchWavelet);
+    assertTrue(fetchWavelet.getRootBlip().getContent().contains(MESSAGE));
+    assertEquals(TITLENEW, fetchWavelet.getTitle());
+  }
+
+}




More information about the kune-commits mailing list