// Copyright 2012 Google Inc. // // 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.google.enterprise.connector.spi; import com.google.enterprise.connector.spiimpl.ValueImpl; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Element; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSOutput; import org.w3c.dom.ls.LSSerializer; import java.io.IOException; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; /** * A user profile document object. * * @author tapasnay * @since 3.0 */ public class SocialUserProfileDocument implements Document { private static List<Value> getValueList(String value) { return Collections.singletonList(Value.getStringValue(value)); } private static List<Value> getValueList(List<String> valueList) { List<Value> values = new ArrayList<Value>(); for (String val : valueList) { values.add(Value.getStringValue(val)); } return values; } private static Value getSingleValue(List<Value> valueList) { if (valueList == null) { return null; } return valueList.get(0); } /** * A colleague object. A colleague of a user is a person who the user normally * works with, may or may not be in the same group. * * @since 3.0 */ public static class ColleagueData { private String identity; private String name; private boolean isInWorkGroup; private String group; private String email; private String title; private String url; /** * Sets identity of colleague. * * @param identity identity (account name) of colleague */ public void setIdentity(String identity) { this.identity = identity; } /** * Gets identity of colleague. * * @return identity of colleague */ public String getIdentity() { return identity; } /** * Sets name of colleague. * * @param name commonly used name of colleague */ public void setName(String name) { this.name = name; } /** * Gets name of colleague. * * @return commonly used name of colleague */ public String getName() { return name; } /** * Sets if colleague is in same work group as user. * * @param isInWorkGroup {@code true} if colleague is in same work group as * user */ public void setInWorkGroup(boolean isInWorkGroup) { this.isInWorkGroup = isInWorkGroup; } /** * Gets whether colleague is in same work group as user. * * @return {@code true} if colleague is in same work group as user */ public boolean isInWorkGroup() { return isInWorkGroup; } /** * Sets work group of colleague. * * @param group work group of colleague */ public void setGroup(String group) { this.group = group; } /** * Gets work group of colleague. * * @return work group of colleague */ public String getGroup() { return group; } /** * Sets emailId of colleague. * * @param email emailId of colleague */ public void setEmail(String email) { this.email = email; } /** * Gets emailId of colleague. * * @return emailId of colleague */ public String getEmail() { return email; } /** * Sets title of colleague. * * @param title title of colleague */ public void setTitle(String title) { this.title = title; } /** * Gets title of colleague. * * @return title of colleague */ public String getTitle() { return title; } /** * Sets URL of colleague. * * @param url URL of the colleague */ public void setUrl(String url) { this.url = url; } /** * Gets URL of colleague. * * @return URL of the colleague */ public String getUrl() { return url; } } /** * Set of properties, besides the special ones. */ private final Map<String, List<Value>> properties = new HashMap<String, List<Value>>(); /** * Colleagues of this user. */ private final List<ColleagueData> colleagues = new ArrayList<ColleagueData>(); /** * Collection name where the userprofile needs to go. */ private String collectionName; /** * Constructor takes collectionName as parameter for the user profile * document. * * @param collectionName name of collection where the profile document needs * to go */ public SocialUserProfileDocument(String collectionName) { this.collectionName = collectionName; } /** * Gets user content which is typically a description of the user in his/her * own words. * * @return user content */ public Value getUserContent() { List<Value> values = properties .get(SocialUserProfileProperties.PROPNAME_USERCONTENT); if ((values == null) || (values.size() == 0)) { return null; } return values.get(0); } /** * Sets user content: typically a description of user in own words. * * @param userContent user content */ public void setUserContent(String userContent) { properties.put(SocialUserProfileProperties.PROPNAME_USERCONTENT, getValueList(userContent)); } /** * Sets skill set of user. * * @param skillText skills */ public void setSkills(List<String> skillText) { properties.put(SocialUserProfileProperties.PROPNAME_SKILLS, getValueList(skillText)); } /** * Gets skills of user. * * @return skills */ public List<Value> getSkills() { return properties.get(SocialUserProfileProperties.PROPNAME_SKILLS); } /** * Sets topics user can be asked about. * * @param askmeAbout topics user can be asked about */ public void setAskmeAbout(List<String> askmeAbout) { properties.put(SocialUserProfileProperties.PROPNAME_ASKMEABOUT, getValueList(askmeAbout)); } /** * Gets topics user can be asked about. * * @return topics user can be asked about */ public List<Value> getAskmeAbout() { return properties.get(SocialUserProfileProperties.PROPNAME_ASKMEABOUT); } /** * Sets user's past projects. * * @param values projects user worked in the past */ public void setPastProjects(List<String> values) { properties.put(SocialUserProfileProperties.PROPNAME_PASTPROJECTS, getValueList(values)); } /** * Gets user's past projects. * * @return projects user worked in the past */ public List<Value> getPastProjects() { return properties.get(SocialUserProfileProperties.PROPNAME_PASTPROJECTS); } /** * Sets whether the profile is public or not. * * @param isPublic true if the profile is public */ public void setPublic(boolean isPublic) { properties.put(SpiConstants.PROPNAME_ISPUBLIC, getValueList(String.valueOf(isPublic))); } /** * Gets whether profile is public. * * @return true if the profile is public */ public boolean getPublic() { ValueImpl value = (ValueImpl) getSingleValue( properties.get(SpiConstants.PROPNAME_ISPUBLIC)); return (value == null) || value.toBoolean(); } /** * Gets user's unique identity. * * @return unique key identifying a user */ public Value getUserKey() { return getSingleValue(properties .get(SocialUserProfileProperties.PROPNAME_ACCOUNTNAME)); } /** * Sets user's unique identity. * * @param userKey unique key identifying a user */ public void setUserKey(String userKey) { properties.put(SocialUserProfileProperties.PROPNAME_ACCOUNTNAME, getValueList(userKey)); } /** * Sets a list of values to a property (maybe beyond the distinguished * properties). * * @param name name of user profile property * @param values list of values of property */ public void setProperty(String name, List<String> values) { properties.put(name, getValueList(values)); } /** * Sets a single value to a property. * * @param name name of property * @param value value of property */ public void setProperty(String name, String value) { properties.put(name, getValueList(value)); } /** * Gets a list of values for a property, the list may be null. * * @param name name of property * @return list of values: may be null */ public List<Value> getProperty(String name) { return properties.get(name); } /** * Sets URL of the profile picture of user. * * @param pictureUrl URL with the profile picture of user */ public void setPictureUrl(String pictureUrl) { properties.put(SocialUserProfileProperties.PROPNAME_PICTUREURL, getValueList(pictureUrl)); } /** * Gets URL of the profile picture. * * @return : profile picture URL */ public Value getPictureUrl() { return getSingleValue(properties .get(SocialUserProfileProperties.PROPNAME_PICTUREURL)); } /** * Sets organization URL of the user. * * @param orgUrl URL of user's organization */ public void setOrgUrl(String orgUrl) { properties.put(SocialUserProfileProperties.PROPNAME_ORGURL, getValueList(orgUrl)); } /** * Gets organization URL of the user. * * @return URL of user's organization */ public Value getOrgUrl() { return getSingleValue(properties .get(SocialUserProfileProperties.PROPNAME_ORGURL)); } /** * Sets list of colleagues of user. This method serializes the list into XML * according to <code>Contacts.xsd</code>. * * @param colleagues list of colleagues of user * @throws RepositoryException */ public void setColleagues(List<ColleagueData> colleagues) throws RepositoryException { this.colleagues.clear(); this.colleagues.addAll(colleagues); try { properties.put(SocialUserProfileProperties.PROPNAME_COLLEAGUES, getValueList(serializeColleagues())); } catch (IOException e) { throw new RepositoryException(e); } } /** * Gets list of colleagues. * * @return list of colleagues of user */ public List<ColleagueData> getColleagues() { return this.colleagues; } private String serializeColleagues() throws IOException, RepositoryException { // Get an instance of factory DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); org.w3c.dom.Document dom; DOMImplementation domImpl; try { // Get an instance of builder DocumentBuilder db = dbf.newDocumentBuilder(); domImpl = db.getDOMImplementation(); // Create an instance of DOM dom = domImpl.createDocument(GSA_NAMESPACE, CONTACTS_ROOT_ELEMENT, null); } catch (ParserConfigurationException pce) { throw new RepositoryException(pce); } // Create the root element for (ColleagueData oneColleague : this.colleagues) { // For each Colleague object create element and attach it to root Element colleagueElem = createColleagueElement(dom, oneColleague); dom.getDocumentElement().appendChild(colleagueElem); } DOMImplementationLS ls = (DOMImplementationLS) domImpl; LSSerializer lss = ls.createLSSerializer(); LSOutput lso = ls.createLSOutput(); StringWriter writer = new StringWriter(); lso.setCharacterStream(writer); lss.write(dom, lso); String result = writer.toString(); return result; } private Element createColleagueElement(org.w3c.dom.Document dom, ColleagueData oneColleague) { try { Element colleagueEle = dom .createElementNS(GSA_NAMESPACE, CONTACT_ELEMENT); colleagueEle .setAttributeNS(GSA_NAMESPACE, "gsa:accountname", URLEncoder.encode( spaceForNullString(oneColleague.identity), "UTF-8")); colleagueEle.setAttributeNS(GSA_NAMESPACE, "gsa:name", URLEncoder.encode(spaceForNullString(oneColleague.name), "UTF-8")); colleagueEle.setAttributeNS(GSA_NAMESPACE, "gsa:email", URLEncoder.encode(spaceForNullString(oneColleague.email), "UTF-8")); colleagueEle.setAttributeNS(GSA_NAMESPACE, "gsa:url", URLEncoder.encode(spaceForNullString(oneColleague.url), "UTF-8")); colleagueEle.setAttributeNS(GSA_NAMESPACE, "gsa:title", URLEncoder.encode(spaceForNullString(oneColleague.title), "UTF-8")); colleagueEle.setAttributeNS(GSA_NAMESPACE, "gsa:group", URLEncoder.encode(spaceForNullString(oneColleague.group), "UTF-8")); colleagueEle.setAttributeNS(GSA_NAMESPACE, "gsa:isinworkinggroup", oneColleague.isInWorkGroup ? "true" : "false"); return colleagueEle; } catch (UnsupportedEncodingException ex) { // ignore: cant happen throw new AssertionError(); } } private String spaceForNullString(String s) { if (s == null) { return ""; } else { return s; } } private final String CONTACT_ELEMENT = "gsa:contact"; private final String CONTACTS_ROOT_ELEMENT = "gsa:Contacts"; private final String GSA_NAMESPACE = "http://www.google.com/schemas/gsa"; /** * Gets colleague list as XML of the form below: * * <pre> * {@code <?xml version="1.0" encoding="UTF-8"?> * <gsa:Contacts xmlns:gsa="http://www.google.com/schemas/gsa" * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> * <gsa:contact gsa:accountname="accountname" gsa:email="email" * gsa:group="group" gsa:isinworkinggroup="true" gsa:name="name" * gsa:title="mytitle" gsa:url="myurl"/> * </gsa:Contacts> } * </pre> * * XSD for the XML is * * <pre> * {@code <?xml version="1.0" encoding="UTF-8"?> * <schema xmlns="http://www.w3.org/2001/XMLSchema" * targetNamespace="http://www.google.com/schemas/gsa" * xmlns:gsa="http://www.google.com/schemas/gsa" * elementFormDefault="qualified"> * <element name="Contacts"> * <complexType> * <sequence> * <element name="contact" maxOccurs="unbounded" minOccurs="1"> * <complexType> * <attribute name="name" type="string" form="qualified" * use="optional" /> * <attribute name="email" type="string" form="qualified" /> * <attribute name="accountname" type="string" form="qualified" * use="required" /> * <attribute name="url" type="string" form="qualified" * use="optional" /> * <attribute name="title" type="string" form="qualified" * use="optional" /> * <attribute name="group" type="string" form="qualified" * use="optional" /> * <attribute name="isinworkinggroup" type="boolean" * form="qualified" use="optional" /> * </complexType> * </element> * </sequence> * </complexType> * </element> * </schema> } * </pre> * * @return colleague list as XML */ public Value getColleagueXml() { return getSingleValue(properties .get(SocialUserProfileProperties.PROPNAME_COLLEAGUES)); } /** * Creates a docId from a user profile. * * @return docId for the user profile document */ private String makeDocId() { try { return SocialCollectionHandler.getDocIdPrefix(collectionName) + URLEncoder.encode(getUserKey().toString(), "UTF-8"); } catch (UnsupportedEncodingException e) { // Can not happen. throw new AssertionError(); } } /** * {@inheritDoc} */ @Override public Property findProperty(String name) { if (name.equals(SpiConstants.PROPNAME_DOCID)) { return new SimpleProperty(getValueList(makeDocId())); } List<Value> list = properties.get(name); return (list == null) ? null : new SimpleProperty(list); } /** * {@inheritDoc} */ @Override public Set<String> getPropertyNames() throws RepositoryException { return properties.keySet(); } }