/*
* © Copyright IBM Corp. 2014
*
* 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 com.ibm.sbt.services.client.connections.profiles;
import static com.ibm.sbt.services.client.base.CommonConstants.AUTH_TYPE;
import static com.ibm.sbt.services.client.base.CommonConstants.CH_COLON;
import static com.ibm.sbt.services.client.base.CommonConstants.COMMA;
import static com.ibm.sbt.services.client.base.CommonConstants.CONTENT_TYPE;
import static com.ibm.sbt.services.client.base.CommonConstants.DOT;
import static com.ibm.sbt.services.client.base.CommonConstants.EMPTY;
import static com.ibm.sbt.services.client.base.CommonConstants.EQUALS;
import static com.ibm.sbt.services.client.base.CommonConstants.IMAGE_;
import static com.ibm.sbt.services.client.base.CommonConstants.IMAGE_JPG;
import static com.ibm.sbt.services.client.base.CommonConstants.JPG;
import static com.ibm.sbt.services.client.base.CommonConstants.LOCATION_HEADER;
import static com.ibm.sbt.services.client.base.ConnectionsConstants.HREF;
import static com.ibm.sbt.services.client.base.ConnectionsConstants.nameSpaceCtx;
import static com.ibm.sbt.services.client.connections.profiles.utils.ProfilesConstants.ACCEPTED;
import static com.ibm.sbt.services.client.connections.profiles.utils.ProfilesConstants.COLLEAGUE;
import static com.ibm.sbt.services.client.connections.profiles.utils.ProfilesConstants.CONNECTION;
import static com.ibm.sbt.services.client.connections.profiles.utils.ProfilesConstants.CONNECTION_TYPE;
import static com.ibm.sbt.services.client.connections.profiles.utils.ProfilesConstants.CONNECTION_UNIQUE_IDENTIFIER;
import static com.ibm.sbt.services.client.connections.profiles.utils.ProfilesConstants.FORMAT;
import static com.ibm.sbt.services.client.connections.profiles.utils.ProfilesConstants.FULL;
import static com.ibm.sbt.services.client.connections.profiles.utils.ProfilesConstants.OUTPUT;
import static com.ibm.sbt.services.client.connections.profiles.utils.ProfilesConstants.OUTPUT_TYPE;
import static com.ibm.sbt.services.client.connections.profiles.utils.ProfilesConstants.PROFILE;
import static com.ibm.sbt.services.client.connections.profiles.utils.ProfilesConstants.PROFILES;
import static com.ibm.sbt.services.client.connections.profiles.utils.ProfilesConstants.VCARD;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.conn.EofSensorInputStream;
import org.w3c.dom.Node;
import com.ibm.commons.util.StringUtil;
import com.ibm.commons.util.io.json.JsonJavaObject;
import com.ibm.commons.xml.xpath.XPathExpression;
import com.ibm.sbt.services.client.ClientService;
import com.ibm.sbt.services.client.ClientServicesException;
import com.ibm.sbt.services.client.Response;
import com.ibm.sbt.services.client.base.AtomFeedHandler;
import com.ibm.sbt.services.client.base.AuthType;
import com.ibm.sbt.services.client.base.BaseService;
import com.ibm.sbt.services.client.base.CommonConstants.HTTPCode;
import com.ibm.sbt.services.client.base.ConnectionsService;
import com.ibm.sbt.services.client.base.IFeedHandler;
import com.ibm.sbt.services.client.base.NamedUrlPart;
import com.ibm.sbt.services.client.base.datahandlers.EntityList;
import com.ibm.sbt.services.client.base.datahandlers.JsonDataHandler;
import com.ibm.sbt.services.client.connections.common.Tag;
import com.ibm.sbt.services.client.connections.profiles.model.ProfileXPath;
import com.ibm.sbt.services.client.connections.profiles.serializers.ColleagueConnectionSerializer;
import com.ibm.sbt.services.client.connections.profiles.serializers.ProfileSerializer;
import com.ibm.sbt.services.client.connections.profiles.utils.Messages;
import com.ibm.sbt.services.client.smartcloud.profiles.ProfileServiceException;
import com.ibm.sbt.services.endpoints.Endpoint;
/**
* The Profiles application of IBM® Connections is a directory of the people in your organization.
* You can use it to find the information you need to form and encourage effective networks.
* In addition to basic information, Profiles catalogs skills such as technical expertise, familiarity with foreign languages, and areas of interest.
*
* @see
* <a href="http://www-10.lotus.com/ldd/appdevwiki.nsf/xpDocViewer.xsp?lookupName=IBM+Connections+4.5+API+Documentation#action=openDocument&res_title=Profiles_API_ic45&content=pdcontent">
* Profiles API</a>
*
* @author Swati Singh
* @author Carlos Manias
*/
public class ProfileService extends ConnectionsService {
private static final long serialVersionUID = -598413531035038479L;
/**
* Create ProfileService instance with default endpoint.
*/
public ProfileService() {
this(DEFAULT_ENDPOINT_NAME, DEFAULT_CACHE_SIZE);
}
/**
* Create ProfileService instance with specified endpoint.
*
* @param endpoint
*/
public ProfileService(String endpoint) {
this(endpoint, DEFAULT_CACHE_SIZE);
}
/**
* Create WikiService instance with specified endpoint.
*
* @param endpoint
*/
public ProfileService(Endpoint endpoint) {
this(endpoint, DEFAULT_CACHE_SIZE);
}
/**
* Create a ProfileService instance with specified endpoint and CacheSize
*
* @param endpoint
* @param cacheSize
* Creates ProfileService with specified endpoint and CacheSize
*/
public ProfileService(String endpoint, int cacheSize) {
super(endpoint, cacheSize);
}
/**
* Create a ProfileService instance with specified endpoint and CacheSize
*
* @param endpoint
* @param cacheSize
* Creates ProfileService with specified endpoint and CacheSize
*/
public ProfileService(Endpoint endpoint, int cacheSize) {
super(endpoint, cacheSize);
}
@Override
protected void initServiceMappingKeys(){
serviceMappingKeys = new String[]{PROFILES};
}
@Override
public NamedUrlPart getAuthType(){
String auth = super.getAuthType().getValue();
auth = AuthType.BASIC.get().equalsIgnoreCase(auth)?EMPTY:auth;
return new NamedUrlPart(AUTH_TYPE, auth);
}
/***************************************************************
* Getting Profile Feeds
****************************************************************/
/**
* Search for a set of profiles that match a specific criteria and return them in a feed.<br>
* You can use this resource to discover someone's user ID. <br>
* When you search by name, the returned feed identifies each person's user ID,
* which you can subsequently use in other types of searches to retrieve more detailed information about a person.<br>
* This method returns a feed of profiles instead of the Atom entry of a single profile.
* If you want to retrieve an Atom entry document, see Retrieving a profile entry. The content element of each returned entry includes the vCard information for the person being represented by the entry.
*
* @param parameters
* list of query string parameters to pass to API
* @return EntityList<Profile>
* @throws ClientServicesException
*/
public EntityList<Profile> searchProfiles(Map<String, String> parameters) throws ClientServicesException {
String url = ProfileUrls.SEARCH.format(this);
return getProfileEntityList(url, parameters);
}
/**
* This method returns a feed of profile as opposed to retrieving the Atom entry of the profile.<br>
* If you want to retrieve an Atom entry document, see Retrieving a profile entry.<br>
* The content element of each returned entry includes the vcard information for the person being represented by the entry.<br>
* In addition, it provides a list of the fully qualified URLs for each IBM® Connections application link displayed in the business card.
*
* @param id
* unique identifier of User , it can either be email or id
* @return Profile
* @throws ClientServicesException
*/
public Profile getProfile(String id) throws ClientServicesException {
return getProfile(id, null);
}
/**
* This method returns a feed of profile as opposed to retrieving the Atom entry of the profile.<br>
* If you want to retrieve an Atom entry document, see Retrieving a profile entry.<br>
* The content element of each returned entry includes the vcard information for the person being represented by the entry.<br>
* In addition, it provides a list of the fully qualified URLs for each IBM® Connections application link displayed in the business card.
*
* @param id
* unique identifier of User , it can either be email or id
* @param parameters
* list of query string parameters to pass to API
* @return Profile
* @throws ClientServicesException
*/
public Profile getProfile(String id, Map<String, String> parameters) throws ClientServicesException {
// TODO: Do a cache lookup first. If cache miss, make a network call to get profile
if (StringUtil.isEmpty(id)){
throw new ClientServicesException(null, Messages.InvalidArgument_1);
}
String url = ProfileUrls.PROFILE.format(this, ProfileParams.userId.get(id));
return getProfileEntity(url, parameters);
}
/**
* Retrieve the profiles of the people who comprise a specific user's report-to chain.
* For example, the profile of the user's manager, that manager's manager, and so on.
* The content element of each returned entry includes the vcard information for the person being represented by the entry.
*
* @param id
* unique identifier of the user whose report to chain is required, it can be email or userID
* @return EntityList<Profile>
* @throws ClientServicesException
*/
public EntityList<Profile> getReportingChain(String id) throws ClientServicesException {
return getReportingChain(id,null);
}
/**
* Retrieve the profiles of the people who comprise a specific user's report-to chain.
* For example, the profile of the user's manager, that manager's manager, and so on.
* The content element of each returned entry includes the vcard information for the person being represented by the entry.
*
* @param id
* unique identifier of the user whose report to chain is required, it can be email or userID
* @param parameters
* list of query string parameters to pass to API
* @return EntityList<Profile>
* @throws ClientServicesException
*/
public EntityList<Profile> getReportingChain (String id, Map<String, String> parameters)throws ClientServicesException {
String url = ProfileUrls.REPORTING_CHAIN.format(this, ProfileParams.userId.get(id));
return getProfileEntityList(url, parameters);
}
/**
* Retrieve the profiles of the people who report to a specific user.
* The content element of each returned entry includes the vcard information for the person being represented by the entry.
*
* @param id
* unique identifier of the user whose direct reports are required, it can be email or userID
* @return EntityList<Profile>
* @throws ClientServicesException
*/
public EntityList<Profile> getPeopleManaged(String id) throws ClientServicesException {
return getPeopleManaged(id,null);
}
/**
* Retrieve the profiles of the people who report to a specific user.
* The content element of each returned entry includes the vcard information for the person being represented by the entry.
*
* @param id
* unique identifier of the user whose direct reports are required, it can be email or userID
* @param parameters
* list of query string parameters to pass to API
* @return EntityList<Profile>
* @throws ClientServicesException
*/
public EntityList<Profile> getPeopleManaged(String id, Map<String, String> parameters)throws ClientServicesException {
String url = ProfileUrls.PEOPLE_MANAGED.format(this, ProfileParams.userId.get(id));
return getProfileEntityList(url, parameters);
}
/**
* Returns a feed that lists the contacts that a person has designated as colleagues. <br>
* You can use this resource to subscribe to a person's list of colleagues.
*
* @param id
* unique identifier of the user whose colleagues are required, it can be email or userID
* @return EntityList<Profile>
* @throws ClientServicesException
*/
public EntityList<Profile> getColleagues(String id) throws ClientServicesException {
return getColleagues(id,null);
}
/**
* Returns a feed that lists the contacts that a person has designated as colleagues. <br>
* You can use this resource to subscribe to a person's list of colleagues.
*
* @param id
* unique identifier of the user whose colleagues are required, it can be email or userID
* @param parameters
* list of query string parameters to pass to API
* @return EntityList<Profile>
* @throws ClientServicesException
*/
public EntityList<Profile> getColleagues(String id, Map<String, String> parameters) throws ClientServicesException {
if (StringUtil.isEmpty(id)){
throw new ClientServicesException(null, Messages.InvalidArgument_1);
}
parameters = getParameters(parameters);
parameters.put(CONNECTION_TYPE, COLLEAGUE);
parameters.put(OUTPUT_TYPE, PROFILE);
String url = ProfileUrls.CONNECTIONS.format(this, ProfileParams.userId.get(id));
return getProfileEntityList(url, parameters);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
//TODO: Get a list of your connections by status where status is accepted, pending and unconfirmed
//////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns an entry of the colleague connection if one exists.
*
* @see
* <a href="http://www-10.lotus.com/ldd/appdevwiki.nsf/xpDocViewer.xsp?lookupName=IBM+Connections+4.0+API+Documentation#action=openDocument&res_title=Checking_whether_two_people_are_colleagues_ic40a&content=pdcontent">
* Checking whether two people are colleagues</a>
*
* @param sourceId
* userid or email of first user
* @param targetId
* userid or email of second user
* @return ColleagueConnection
* @throws ClientServicesException
*/
public ColleagueConnection checkColleague(String sourceId, String targetId) throws ClientServicesException {
return checkColleague(sourceId, targetId, null);
}
/**
* Returns an entry of the colleague connection if one exists.
*
* @param sourceId
* userid or email of first user
* @param targetId
* userid or email of second user
* @param parameters
* list of query string parameters to pass to API
* @return ColleagueConnection
* @throws ClientServicesException
*/
public ColleagueConnection checkColleague(String sourceId, String targetId, Map<String, String> parameters) throws ClientServicesException {
String url = ProfileUrls.CHECK_COLLEAGUE.format(this, ProfileParams.sourceId.get(sourceId), ProfileParams.targetId.get(targetId));
return getColleagueConnectionEntity(url, parameters);
}
/**
* Retrieve the Colleagues In Common feed to find out what colleagues two people have in common.
* The feed contains entries that represent colleague connections. Each entry contains the following information:
* <li> A colleague that the two people share in common
* <li> The status of the connection
* The output is displayed as a profile entry.
*
* @param sourceId
* userid or email of first user
* @param targetId
* userid or email of second user
* @return EntityList<Profile>
* @throws ClientServicesException
*/
public EntityList<Profile> getCommonColleagues(String sourceId, String targetId) throws ClientServicesException {
return getCommonColleagues(sourceId, targetId, null);
}
/**
* Retrieve the Colleagues In Common feed to find out what colleagues two people have in common.
* The feed contains entries that represent colleague connections. Each entry contains the following information:
* <li> A colleague that the two people share in common
* <li> The status of the connection
* The output is displayed as a profile entry.
*
* @param sourceId
* userid or email of first user
* @param targetId
* userid or email of second user
* @param parameters
* list of query string parameters to pass to API
* @return EntityList<Profile>
* @throws ClientServicesException
*/
public EntityList<Profile> getCommonColleagues(String sourceId, String targetId, Map<String, String> parameters) throws ClientServicesException {
if (StringUtil.isEmpty(sourceId)) {
throw new ClientServicesException(null, Messages.InvalidArgument_4);
}
if (StringUtil.isEmpty(targetId)) {
throw new ClientServicesException(null, Messages.InvalidArgument_5);
}
StringBuilder value = new StringBuilder(sourceId);
value = value.append(COMMA).append(targetId);
parameters = getParameters(parameters);
parameters.put(CONNECTION_TYPE, COLLEAGUE);
parameters.put(OUTPUT_TYPE, PROFILE);
String url = ProfileUrls.CONNECTIONS_IN_COMMON.format(this, ProfileParams.userId.get(value.toString()));
return getProfileEntityList(url, parameters);
}
/**
* Retrieve the Colleagues In Common feed to find out what colleagues two people have in common.
* The feed contains entries that represent colleague connections. Each entry contains the following information:
* <li> A colleague that the two people share in common
* <li> The status of the connection
* The output is displayed as a connection entry.
*
* @param sourceId
* userid or email of first user
* @param targetId
* userid or email of second user
* @return EntityList<ColleagueConnection>
* @throws ClientServicesException
*/
public EntityList<ColleagueConnection> getCommonColleagueConnections(String sourceId, String targetId) throws ClientServicesException {
return getCommonColleagueConnections(sourceId, targetId, null);
}
/**
* Retrieve the Colleagues In Common feed to find out what colleagues two people have in common.
* The feed contains entries that represent colleague connections. Each entry contains the following information:
* <li> A colleague that the two people share in common
* <li> The status of the connection
* The output is displayed as a connection entry.
*
* @param sourceId
* userid or email of first user
* @param targetId
* userid or email of second user
* @param parameters
* list of query string parameters to pass to API
* @return EntityList<ColleagueConnection>
* @throws ClientServicesException
*/
public EntityList<ColleagueConnection> getCommonColleagueConnections(String sourceId, String targetId, Map<String, String> parameters) throws ClientServicesException {
if (StringUtil.isEmpty(sourceId)) {
throw new ClientServicesException(null, Messages.InvalidArgument_4);
}
if (StringUtil.isEmpty(targetId)) {
throw new ClientServicesException(null, Messages.InvalidArgument_5);
}
parameters = getParameters(parameters);
StringBuilder value = new StringBuilder(sourceId);
value = value.append(COMMA).append(targetId);
parameters.put(CONNECTION_TYPE, COLLEAGUE);
parameters.put(OUTPUT_TYPE, CONNECTION);
String url = ProfileUrls.CONNECTIONS_IN_COMMON.format(this, ProfileParams.userId.get(value.toString()));
return getColleagueConnectionEntityList(url, parameters);
}
////////////////////////////////////////////
//TODO: Get a person's status update entries
////////////////////////////////////////////
//////////////////////////////////////////////////////
//TODO: Get all the comments associated with a message
//////////////////////////////////////////////////////
///////////////////////////////////////////
//TODO: Get the messages of your colleagues
///////////////////////////////////////////
///////////////////////////////
//TODO: Get all status messages
///////////////////////////////
////////////////////////////////////////////////////
//TODO: Get the status messages of a list of people
////////////////////////////////////////////////////
/***************************************************************
* Working with pronunciation files
****************************************************************/
////////////////////////////////////////////////////////////////////////////////
//TODO: ALL WORKING PRONUNCIATION FILES
////////////////////////////////////////////////////////////////////////////////
/***************************************************************
* Working with profile extensions
****************************************************************/
////////////////////////////////////////////////////////////////////////////////
//TODO: MOST WORKING PROFILE EXTENSIONS
////////////////////////////////////////////////////////////////////////////////
/**
* Returns a mapping containing the extended attributes for the entry.<bt/>
* This method execute a xhr call to the back end for every attribute.
*
* @param p the profile to use. has to be a full profile, to obtain all the extended attributes links
* @return a map containing the id of the attribute as key and the attribute value as value<br/>
* the map can contain object of type InputStream, Node, String, according to the return content type
* @throws ClientServicesException
*/
public Map<String,Object> getExtendedAttributes(Profile p) throws ClientServicesException {
Map<String, Object> ret = new HashMap<String, Object>();
List<Node> attributes = (List<Node>) p.getDataHandler().getEntries(ProfileXPath.extendedAttributes);
for (Node link :attributes) {
String extUrl = link.getAttributes().getNamedItem(HREF).getTextContent();
String extId = link.getAttributes().getNamedItem("snx:extensionId").getTextContent();
Response resp;
resp = getEndpoint().xhrGet(extUrl);
Object extValue= resp.getData();
if (resp.getData() instanceof EofSensorInputStream) {
//a EofSensorInputStream leaves the connection open until it is read fully
//so we read it before serving it to the client terminating the connection
try {
extValue = new ByteArrayInputStream(IOUtils.toByteArray((EofSensorInputStream)resp.getData()));
} catch (Exception e) {
throw new ClientServicesException(e,"Exception reading " + extUrl);
}
}
ret.put(extId, extValue);
}
return ret;
}
/***************************************************************
* Working with profile photos
****************************************************************/
////////////////////////////////////////////////////
//TODO: Adding a photo to a profile
////////////////////////////////////////////////////
////////////////////////////////////////////////////
//TODO: Removing a photo from a profile
////////////////////////////////////////////////////
////////////////////////////////////////////////////
//TODO: Retrieving a profile photo
////////////////////////////////////////////////////
/**
* To replace the image file that supplies the photo for a person's profile,
* send a binary image file to the web address defined in the image file link returned by the Profile's entry document. <br>
* You can only replace a photo if you are the profile owner or an administrator.
* See Authenticating requests for information about how to authenticate the request. <br>
*
* @param File
* image to be uploaded as profile photo
* @param userid
* @throws ClientServicesException
*/
public void updateProfilePhoto(File file, String userId) throws ClientServicesException {
if (file == null || !file.canRead()) {
throw new ClientServicesException(null, Messages.MessageCannotReadFile,
file.getAbsolutePath());
}
String name = file.getName();
int dot = StringUtil.lastIndexOfIgnoreCase(name, DOT);
String ext = "";
if (dot > -1) {
ext = name.substring(dot + 1); // add one for the dot!
}
if (!StringUtil.isEmpty(ext)) {
Map<String, String> headers = new HashMap<String, String>();
if (StringUtil.equalsIgnoreCase(ext, JPG)) {
headers.put(CONTENT_TYPE, IMAGE_JPG); // content-type should be image/jpeg for file extension - jpeg/jpg
} else {
headers.put(CONTENT_TYPE, IMAGE_ + ext);
}
String url = ProfileUrls.PHOTO.format(this, ProfileParams.userId.get(userId));
Response response = getClientService().put(url, null, headers, file, ClientService.FORMAT_NULL);
checkResponseCode(response, HTTPCode.OK);
}
}
/***************************************************************
* Working with colleague connections
****************************************************************/
/**
* To invite a person to become your colleague, send an Atom entry document containing the connection resource to the person's colleague connections feed.<br>
* To find a person's colleague connections feed, you can search for the person by name.
* From the returned feed, find the person and retrieve her associated user ID, and then use the user ID
* to retrieve the person's full feed, which includes a link to her colleague connections feed. <br>
* After you send the invitation, the connection is added to your connections in an unconfirmed state.
* The connection is added to the connections of the person you invited in a pending state.
* See Accepting an invitation to become a colleague or Deleting connections for information about how to accept or decline an invitation. <br>
* See Authenticating requests for information about how to authenticate the request.<br>
* A default Invite message is used while sending the invite
*
* @param id
* unique identifier of the user to whom the invite is to be sent, it can be email or userID
* @return Id of the Connection
* @throws ProfileServiceException
*/
public String sendInvite(String id)throws ClientServicesException {
String defaultInviteMsg = Messages.SendInviteMsg;
return sendInvite(id, defaultInviteMsg);
}
/**
* To invite a person to become your colleague, send an Atom entry document containing the connection resource to the person's colleague connections feed.<br>
* To find a person's colleague connections feed, you can search for the person by name.
* From the returned feed, find the person and retrieve her associated user ID, and then use the user ID
* to retrieve the person's full feed, which includes a link to her colleague connections feed. <br>
* After you send the invitation, the connection is added to your connections in an unconfirmed state.
* The connection is added to the connections of the person you invited in a pending state.
* See Accepting an invitation to become a colleague or Deleting connections for information about how to accept or decline an invitation. <br>
* See Authenticating requests for information about how to authenticate the request.<br>
* A default Invite message is used while sending the invite
*
* @param id
* unique identifier of the user to whom the invite is to be sent, it can be email or userID
* @param inviteMsg
* Invite message to the other user
* @return Id of the Connection
* @throws ProfileServiceException
*/
public String sendInvite(String id, String inviteMsg)throws ClientServicesException {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put(CONNECTION_TYPE, COLLEAGUE);
String payload = constructSendInviteRequestBody(inviteMsg);
String url = ProfileUrls.CONNECTIONS.format(this, ProfileParams.userId.get(id));
Response response = createData(url, parameters, payload);
checkResponseCode(response, HTTPCode.CREATED);
return extractConnectionIdFromHeaders(response);
}
/**
* To remove an existing colleague relationship from your profile,
* or to decline an invitation to become a colleague, use this method. <br>
* Only a participant in the colleague relationship or an invitee to join a colleague relationship
* can delete the connection. Deleted connections cannot be restored.
* See Authenticating requests for information about how to authenticate the request.
*
* @param connectionId
* unique id of the connection
* @throws ClientServicesException
*/
public void deleteInvite(String connectionId)throws ClientServicesException{
if (StringUtil.isEmpty(connectionId)) {
throw new ClientServicesException(null, Messages.InvalidArgument_2);
}
String url = ProfileUrls.CONNECTION.format(this, ProfileUrls.getConnectionId(connectionId));
Response response = deleteData(url, null, connectionId);
checkResponseCode(response, HTTPCode.OK);
}
/**
* To retrieve complete information about a colleague relationship,
* use the edit link found in the connection entry in the colleague connections feed. <bR>
* You can use this operation to obtain connection information that you want to preserve prior to accepting an invitation.
* See Accepting an invitation to become a colleague for more information. <br>
* This method returns the Atom entry of a single connection entry as opposed to a feed of all the connection entries.
* If you want to retrieve a feed, see Searching for a person's colleagues. <br>
* See Authenticating requests for information about how to authenticate the request.
*
* @param id
* unique identifier of the user whose colleagues are required, it can be email or userID
* @return EntityList<ColleagueConnection>
* @throws ClientServicesException
*/
public EntityList<ColleagueConnection> getColleagueConnections(String id) throws ClientServicesException {
return getColleagueConnections(id,null);
}
/**
* To retrieve complete information about a colleague relationship,
* use the edit link found in the connection entry in the colleague connections feed. <bR>
* You can use this operation to obtain connection information that you want to preserve prior to accepting an invitation.
* See Accepting an invitation to become a colleague for more information. <br>
* This method returns the Atom entry of a single connection entry as opposed to a feed of all the connection entries.
* If you want to retrieve a feed, see Searching for a person's colleagues. <br>
* See Authenticating requests for information about how to authenticate the request.
*
* @param id
* unique identifier of the user whose colleagues are required, it can be email or userID
* @param parameters
* list of query string parameters to pass to API
* @return EntityList<ColleagueConnection>
* @throws ClientServicesException
*/
public EntityList<ColleagueConnection> getColleagueConnections(String id, Map<String, String> parameters) throws ClientServicesException {
parameters = getParameters(parameters);
parameters.put(CONNECTION_TYPE, COLLEAGUE);
parameters.put(OUTPUT_TYPE, CONNECTION);
String url = ProfileUrls.CONNECTIONS.format(this, ProfileParams.userId.get(id));
return getColleagueConnectionEntityList(url, parameters);
}
/**
* To accept an invitation to be a colleague, send an updated connection document
* in Atom format to the existing connection's edit web address.<br>
* After you accept a connection, the status of the connection in your connections
* is changed from pending to accepted and the status of the connection in the invitee's list
* of connections is changed from unconfirmed to accepted.<br>
* To decline the invitation, delete it by sending a DELETE HTTP request to the resource.
* All existing connection information will be replaced with the new data.<br>
* To avoid deleting all existing data, retrieve any data you want to retain first,
* and send it back with this request.
* See Inviting a person to become your colleague for more information.<br>
* See Authenticating requests for information about how to authenticate the request.
*
* @param ColleagueConnection
* @throws ClientServicesException
*
*/
public void acceptInvite(ColleagueConnection connection)throws ClientServicesException{
if (connection == null) {
throw new ClientServicesException(null, Messages.InvalidArgument_6);
}
String payload = constructAcceptInviteRequestBody(connection, ACCEPTED);
String url = ProfileUrls.CONNECTION.format(this, ProfileUrls.getConnectionId(connection.getConnectionId()));
Response response = updateData(url, null, payload, connection.getConnectionId());
checkResponseCode(response, HTTPCode.OK);
}
/***************************************************************
* Working with update messages and comments
****************************************************************/
////////////////////////////////////////////////////////////////////////////////
//TODO: ALL WORKING UPDATE MESSAGES AND COMMENTS
////////////////////////////////////////////////////////////////////////////////
/***************************************************************
* Working with status messages
****************************************************************/
////////////////////////////////////////////////////////////////////////////////
//TODO: ALL WORKING STATUS MESSAGES
////////////////////////////////////////////////////////////////////////////////
/***************************************************************
* Working with profiles
****************************************************************/
////////////////////////////////////////////////////////////////////////////////
//TODO: Retrieving a profile entry. Uses the url now only used in ProfileAdmin
////////////////////////////////////////////////////////////////////////////////
/**
* To update your profile entry, send an updated profile entry document
* in Atom format to the existing profile's edit web address.<br>
* All existing profile entry information is replaced with the new data.
* To avoid deleting all existing data, retrieve any data you want to retain first,
* and send it back with this request. For example,
* if you want to add a new tag to a profile entry, retrieve the existing tags,
* and send them all back with the new tag in the update request.
* See Retrieving a profile entry for more information.<br>
* To find out which fields in a particular profile can be edited,
* look for the list of <editableField> elements in the service document of the person
* whose profile you want to edit.
* You cannot programmatically change which fields can be edited;
* that can only be done using wsadmin commands.
* See Customizing the Profiles user interface for more details.
* However, you can change the values stored in the editable fields for a profile
* by specifying new values for the editable fields represented as corresponding vCard values.<br>
* In addition to the default set of fields available for a profile that can be configured as editable by the administrator,
* the administrator can also add custom fields to a profile.
* Custom fields are added using extensions;
* see Adding custom extension attributes for Profiles for more details.
* For information about how to edit the value of a custom field, see Working with profile extensions.<br>
* To get the rel="edit" link for a specific person's profile,
* retrieve a feed of the profile and specify the output=vcard parameter on the request.
* See Searching a user's profile for more details.<br>
* Users can only update their own profiles.
* See Authenticating requests for information about how to authenticate the request.<br>
*
* @param Profile
* @throws ClientServicesException
*/
public void updateProfile(Profile profile) throws ClientServicesException {
if (profile == null) {
throw new ClientServicesException(null, Messages.InvalidArgument_3);
}
Map<String, String> parameters = new HashMap<String, String>();
parameters.put(OUTPUT, VCARD);
parameters.put(FORMAT, FULL);
String id = profile.getUserid();
String updateProfilePayload = constructUpdateRequestBody(profile);
String updateUrl = ProfileUrls.PROFILE_ENTRY.format(this, ProfileParams.userId.get(id));
Response response = updateData(updateUrl, parameters,updateProfilePayload, ProfileParams.userId.getParamName(profile.getAsString("uid")));
checkResponseCode(response, HTTPCode.OK);
profile.clearFieldsMap();
}
/***************************************************************
* Working with profile tags
****************************************************************/
/**
* To retrieve the tags assigned to a profile from the Profiles tag collection,
* use a HTTP GET request to retrieve the tags category document for that profile.<br>
* You can retrieve tags created by any user for any user.
*
* @param id
* unique identifier of the user whose tags are required, it can be email or userKey
* @return EntityList≶Tag>
* @throws ClientServicesException
*/
public EntityList<Tag> getTags(String id) throws ClientServicesException {
return getTags(id,null);
}
/**
* To retrieve the tags assigned to a profile from the Profiles tag collection,
* use a HTTP GET request to retrieve the tags category document for that profile.<br>
* You can retrieve tags created by any user for any user.
*
* @param id
* unique identifier of the user whose tags are required, it can be email or userKey
* @param parameters
* list of query string parameters to pass to API
* @return EntityList≶Tag>
* @throws ClientServicesException
*/
public EntityList<Tag> getTags(String id, Map<String, String> parameters) throws ClientServicesException {
String url = ProfileUrls.GET_TAGS.format(this, ProfileParams.targetId.get(id));
return getTagEntityList(url, parameters);
}
/**
* Creating, updating and deleting tags is done with the same operation.<br>
* To update the tags that one user created and assigned to another user's profile,
* use a HTTP PUT request to update the tags listed in the tag creator's tags category document.<br>
* When you update profile tags, the existing tag information is replaced with the new data.
* To avoid deleting all existing tags, retrieve the tags that you want to retain first,
* and send them back with this request. See Retrieving profile tags for more information.<br>
* You can add tags to anyone's collection. You can only replace tags created by the user whose credentials
* you provided to authenticate with the server. You can remove tags from the tag collection for your profile
* by leaving them out of the updated set. <br>
* See Authenticating requests for information about how to authenticate the request.
*
* @param sourceId
* unique identifier of the user who wants to add tags to a profile
* @param targetId
* unique identifier of the user whose profile is going to be tagged
* @param profile
* profile to be tagged, containing all the tags, both existing and new
* @param tags Comma-separated list of tags to add to the profile
* @throws ClientServicesException
*/
public void addTags(String sourceId, String targetId, Profile profile) throws ClientServicesException{
if (StringUtil.isEmpty(sourceId)){
throw new ClientServicesException(null, Messages.InvalidArgument_4);
}
if (StringUtil.isEmpty(targetId)){
throw new ClientServicesException(null, Messages.InvalidArgument_5);
}
String serviceUrl = ProfileUrls.TAGS.format(this,
ProfileParams.sourceId.get(sourceId),
ProfileParams.targetId.get(targetId));
ProfileSerializer serializer = new ProfileSerializer(profile);
Response response = updateData(serviceUrl, null, serializer.tagsPayload(), null);
checkResponseCode(response, HTTPCode.OK);
}
/***************************************************************
* Working with profile types
****************************************************************/
////////////////////////////////////////////////////////////////////////////////
//TODO: ALL WORKING WITH PROFILE TYPES
////////////////////////////////////////////////////////////////////////////////
/***************************************************************
* Miscellaneous methods
****************************************************************/
/**
* Returns the userid of the currently connected user
*
* @return
* @throws ClientServicesException
*/
public String getMyUserId() throws ClientServicesException{
String id = "";
String peopleApiUrl = ProfileUrls.MY_USER_ID.format(this);
Response feed = getClientService().get(peopleApiUrl);
JsonDataHandler dataHandler = new JsonDataHandler((JsonJavaObject)feed.getData());
id = dataHandler.getAsString("entry/id");
id = id.substring(id.lastIndexOf(CH_COLON)+1, id.length());
return id;
}
/**
* Returns the profile of the currently connected user
*
* @return
* @throws ClientServicesException
*/
public Profile getMyProfile() throws ClientServicesException {
return getProfile(getMyUserId(), null);
}
/***************************************************************
* FeedHandlers for each entity type
****************************************************************/
/**
* Factory method to instantiate a FeedHandler for Profiles
* @return IFeedHandler<Profile>
*/
public IFeedHandler<Profile> getProfileFeedHandler() {
return new AtomFeedHandler<Profile>(this) {
@Override
protected Profile entityInstance(BaseService service, Node node, XPathExpression xpath) {
return new Profile(service, node, nameSpaceCtx, xpath);
}
};
}
/**
* Factory method to instantiate a FeedHandler for ColleagueConnections
* @return IFeedHandler<ColleagueConnection>
*/
public IFeedHandler<ColleagueConnection> getColleagueFeedHandler() {
return new AtomFeedHandler<ColleagueConnection>(this, false) {
@Override
protected ColleagueConnection entityInstance(BaseService service, Node node, XPathExpression xpath) {
return new ColleagueConnection(service, node, nameSpaceCtx, xpath);
}
};
}
/**
* Factory method to instantiate a FeedHandler for Tags
* @return IFeedHandler<Tag>
*/
public IFeedHandler<Tag> getTagFeedHandler() {
return new AtomFeedHandler<Tag>(this) {
@Override
protected Tag entityInstance(BaseService service, Node node, XPathExpression xpath) {
return new Tag(service, node, nameSpaceCtx, xpath);
}
};
}
/***************************************************************
* Factory methods
****************************************************************/
protected Profile getProfileEntity(String requestUrl, Map<String, String> parameters) throws ClientServicesException {
return getEntity(requestUrl, parameters, getProfileFeedHandler());
}
protected ColleagueConnection getColleagueConnectionEntity(String requestUrl, Map<String, String> parameters) throws ClientServicesException {
return getEntity(requestUrl, parameters, getColleagueFeedHandler());
}
protected EntityList<Profile> getProfileEntityList(String requestUrl, Map<String, String> parameters) throws ClientServicesException {
return getEntities(requestUrl, parameters, getProfileFeedHandler());
}
protected EntityList<ColleagueConnection> getColleagueConnectionEntityList(String requestUrl, Map<String, String> parameters) throws ClientServicesException {
return getEntities(requestUrl, parameters, getColleagueFeedHandler());
}
protected EntityList<Tag> getTagEntityList(String requestUrl, Map<String, String> parameters) throws ClientServicesException {
return getEntities(requestUrl, parameters, getTagFeedHandler());
}
/***************************************************************
* Utility methods
****************************************************************/
/*
* This method is used by ProfileService wrapper methods to construct request body for Add operations
* @return String
*/
protected String constructCreateRequestBody(Profile profile) {
ProfileSerializer serializer = new ProfileSerializer(profile);
return serializer.createPayload();
}
/*
* This method is used by ProfileService wrapper methods to construct request body for Update operations
* @return String
*/
protected String constructUpdateRequestBody(Profile profile) {
ProfileSerializer serializer = new ProfileSerializer(profile);
return serializer.updatePayload();
}
/*
* This method is used by ProfileService wrapper methods to construct request body for Add operations
* @return String
*/
protected String constructAcceptInviteRequestBody(ColleagueConnection connectionEntry, String action) {
ColleagueConnectionSerializer serializer = new ColleagueConnectionSerializer(connectionEntry);
return serializer.acceptInvitePayload();
}
/*
* This method is used by ProfileService wrapper methods to construct request body for Add operations
* @return String
* @throws ProfileServiceException
*/
protected String constructSendInviteRequestBody(String inviteMsg) throws ClientServicesException {
ColleagueConnection colleagueConnection = new ColleagueConnection(this, null);
colleagueConnection.setContent(inviteMsg);
ColleagueConnectionSerializer serializer = new ColleagueConnectionSerializer(colleagueConnection);
return serializer.sendInvitePayload();
}
protected String extractConnectionIdFromHeaders(Response requestData){
Header header = requestData.getResponse().getFirstHeader(LOCATION_HEADER);
String urlLocation = header!=null?header.getValue():EMPTY;
return urlLocation.substring(urlLocation.indexOf(CONNECTION_UNIQUE_IDENTIFIER+EQUALS) + (CONNECTION_UNIQUE_IDENTIFIER+EQUALS).length());
}
}