/**
* $Revision$
* $Date$
*
* Copyright (C) 2005-2008 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.openfire.clearspace;
import org.dom4j.Element;
import org.dom4j.Node;
import org.jivesoftware.openfire.XMPPServer;
import static org.jivesoftware.openfire.clearspace.ClearspaceManager.HttpType.GET;
import static org.jivesoftware.openfire.clearspace.WSUtils.getReturn;
import static org.jivesoftware.openfire.clearspace.WSUtils.parseStringArray;
import org.jivesoftware.openfire.group.Group;
import org.jivesoftware.openfire.group.GroupAlreadyExistsException;
import org.jivesoftware.openfire.group.GroupNotFoundException;
import org.jivesoftware.openfire.group.GroupProvider;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.xmpp.packet.JID;
import java.util.*;
/**
* @author Daniel Henninger
*/
public class ClearspaceGroupProvider implements GroupProvider {
protected static final String URL_PREFIX = "socialGroupService/";
private static final String TYPE_ID_OWNER = "0";
private static final String TYPE_ID_MEMBER = "1";
public ClearspaceGroupProvider() {
}
public Group createGroup(String name) throws UnsupportedOperationException, GroupAlreadyExistsException {
throw new UnsupportedOperationException("Could not create groups.");
}
public void deleteGroup(String name) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Could not delete groups.");
}
public Group getGroup(String name) throws GroupNotFoundException {
return translateGroup(getGroupByName(name));
}
public void setName(String oldName, String newName) throws UnsupportedOperationException, GroupAlreadyExistsException {
throw new UnsupportedOperationException("Could not modify groups.");
}
public void setDescription(String name, String description) throws GroupNotFoundException {
throw new UnsupportedOperationException("Could not modify groups.");
}
public int getGroupCount() {
try {
String path = URL_PREFIX + "socialGroupCount";
Element element = ClearspaceManager.getInstance().executeRequest(GET, path);
return Integer.valueOf(getReturn(element));
} catch (Exception e) {
// It is not supported exception, wrap it into an UnsupportedOperationException
throw new UnsupportedOperationException("Unexpected error", e);
}
}
public Collection<String> getSharedGroupsNames() {
// Return all social group names since every social group is a shared group
return getGroupNames();
}
public Collection<String> getGroupNames() {
try {
String path = URL_PREFIX + "socialGroupNames";
Element element = ClearspaceManager.getInstance().executeRequest(GET, path);
return parseStringArray(element);
} catch (Exception e) {
// It is not supported exception, wrap it into an UnsupportedOperationException
throw new UnsupportedOperationException("Unexpected error", e);
}
}
public Collection<String> getGroupNames(int startIndex, int numResults) {
try {
String path = URL_PREFIX + "socialGroupNamesBounded/" + startIndex + "/" + numResults;
Element element = ClearspaceManager.getInstance().executeRequest(GET, path);
return parseStringArray(element);
} catch (Exception e) {
// It is not supported exception, wrap it into an UnsupportedOperationException
throw new UnsupportedOperationException("Unexpected error", e);
}
}
public Collection<String> getGroupNames(JID user) {
try {
long userID = ClearspaceManager.getInstance().getUserID(user);
String path = URL_PREFIX + "userSocialGroupNames/" + userID;
Element element = ClearspaceManager.getInstance().executeRequest(GET, path);
return parseStringArray(element);
} catch (UserNotFoundException e) {
throw new UnsupportedOperationException("User not found", e);
} catch (Exception e) {
// It is not supported exception, wrap it into an UnsupportedOperationException
throw new UnsupportedOperationException("Unexpected error", e);
}
}
public void addMember(String groupName, JID user, boolean administrator) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Could not modify groups.");
}
public void updateMember(String groupName, JID user, boolean administrator) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Could not modify groups.");
}
public void deleteMember(String groupName, JID user) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Could not modify groups.");
}
public boolean isReadOnly() {
return true;
}
public Collection<String> search(String query) {
throw new UnsupportedOperationException("Group search is not supported");
}
public Collection<String> search(String query, int startIndex, int numResults) {
throw new UnsupportedOperationException("Group search is not supported");
}
public boolean isSearchSupported() {
return false;
}
/**
* Translate a XML respose of a group to a <code>Group</code>.
*
* @param responseNode the XML representation of a CS group.
* @return the group that corresponds to the XML.
*/
private Group translateGroup(Element responseNode) {
Node groupNode = responseNode.selectSingleNode("return");
// Gets the CS DISPLAY NAME that is OF NAME
String name = groupNode.selectSingleNode("displayName").getText();
// Gets the CS NAME that is OF DISPLAY NAME
String displayName = groupNode.selectSingleNode("name").getText();
// Gets the group ID
long id = Long.parseLong(groupNode.selectSingleNode("ID").getText());
// Gets the group type
int type = Integer.parseInt(groupNode.selectSingleNode("typeID").getText());
// Gets the group description if it exist
String description = null;
Node tmpNode = groupNode.selectSingleNode("description");
if (tmpNode != null) {
description = tmpNode.getText();
}
// Get the members and administrators
Collection<JID> members = new ArrayList<JID>();
Collection<JID> administrators = new ArrayList<JID>();
try {
XMPPServer server = XMPPServer.getInstance();
// Gets the JID from the response
List<Element> membersElement = (List<Element>) getGroupMembers(id).elements("return");
for (Element memberElement : membersElement) {
String username = memberElement.element("user").element("username").getText();
// Escape username to accept usernames with @ or spaces
String escapedUsername = JID.escapeNode(username);
String typeID = memberElement.element("typeID").getText();
if (TYPE_ID_OWNER.equals(typeID)) {
administrators.add(server.createJID(escapedUsername, null));
} else if (TYPE_ID_MEMBER.equals(typeID)) {
members.add(server.createJID(escapedUsername, null));
} else {
// nothing to do, waiting for approval
}
}
} catch (GroupNotFoundException e) {
// this won't happen, the group exists.
}
Map<String, String> properties = new HashMap<String, String>();
// Type 0 is OPEN
if (type == 0) {
properties.put("sharedRoster.showInRoster", "everybody");
} else {
// Types 1, 2 or 3 are MEMBER_ONLY, PRIVATE, SECRET
properties.put("sharedRoster.showInRoster", "onlyGroup");
}
properties.put("sharedRoster.displayName", displayName);
properties.put("sharedRoster.groupList", "");
// Creates the group
// There are some interesting things happening here.
// If this is the first time that this group is loaded from CS, the OF will save this properties.
// If this is not the first time and these properties haven't changed, then nothing happens
// If this is not the first time but these properties have changed, then OF will update it's saved data.
// And this is OK, event if this "getGroup" is to be used in a "change group properties event", the group should
// always show the last information.
return new Group(name, description, members, administrators, properties);
}
/**
* Returns a group by its name.
*
* @param name the name of the group to retrive.
* @return the group.
* @throws GroupNotFoundException if a group with that name doesn't exist or there is a problem getting it.
*/
private Element getGroupByName(String name) throws GroupNotFoundException {
try {
// Encode potentially non-ASCII characters
name = URLUTF8Encoder.encode(name);
String path = URL_PREFIX + "socialGroupsByName/" + name;
return ClearspaceManager.getInstance().executeRequest(GET, path);
} catch (Exception e) {
// It is not supported exception, wrap it into a GroupNotFoundException
throw new GroupNotFoundException("Unexpected error", e);
}
}
/**
* Returns the all the members of the group. It continas the onwers and the members of the group.
*
* @param groupID the group id to return the members of.
* @return all the members of the group.
* @throws GroupNotFoundException if the groups doesn't exist or there is a problem getting the members.
*/
private Element getGroupMembers(long groupID) throws GroupNotFoundException {
try {
// Gets the members and administrators
String path = URL_PREFIX + "members/" + groupID;
return ClearspaceManager.getInstance().executeRequest(GET, path);
} catch (Exception e) {
// It is not supported exception, wrap it into a GroupNotFoundException
throw new GroupNotFoundException("Unexpected error", e);
}
}
}