Since the Social 1.1.0, the activity plug-in feature was introduced that enables the activity composer extension and custom UI component to be used for displaying one activity by its type.
At first, you should have an idea about the UI Extension Framework. If you have already worked with the UI Extension Framework, it's really easy to create the activity plug-in. If no, you have chance to work with it visiting UI Extension Framework.
("Project Code can be downloadable here")
When an activity is displayed, UIActivityFactory will look for its registered custom activity display by activity's type. If not found, UIDefaultActivity will be called for displaying that activity.
For example, in Social, there is an activity of type "exosocial:spaces" created by SpaceActivityPublisher. If you want to display it with our own UI component instead of default ones.
First, create a sample project:
mvn archetype:generate Choose archetype: Choose a number: 76 Choose version: 1 Define value for property 'groupId': : org.exoplatform.social.samples Define value for property 'artifactId': : exo.social.samples.activity-plugin Define value for property 'version': 1.0-SNAPSHOT: 1.0.0-SNAPSHOT Define value for property 'package': org.exoplatform.social.samples: org.exoplatform.social.samples.activityPlugin Confirm properties configuration: groupId: org.exoplatform.social.samples artifactId: exo.social.samples.activity-plugin version: 1.0.0-SNAPSHOT package: org.exoplatform.social.samples.activityPlugin Y: y
Edit the pom.xml file as follows.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.exoplatform.social</groupId>
<artifactId>social-project</artifactId>
<version>1.1.0-GA</version>
</parent>
<groupId>org.exoplatform.social.samples</groupId>
<artifactId>exo.social.samples.activity-plugin</artifactId>
<packaging>jar</packaging>
<version>1.1.0-GA</version>
<name>exo.social.samples.activity-plugin</name>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<outputDirectory>target/classes</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.gtmpl</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
<dependencies>
<dependency>
<groupId>org.exoplatform.portal</groupId>
<artifactId>exo.portal.webui.core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.exoplatform.portal</groupId>
<artifactId>exo.portal.webui.portal</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.exoplatform.social</groupId>
<artifactId>exo.social.component.core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.exoplatform.social</groupId>
<artifactId>exo.social.component.webui</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.exoplatform.social</groupId>
<artifactId>exo.social.component.service</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
To use the custom UI component for displaying its activity, we need a subclass of BaseUIActivity. We call this UISpaceSimpleActivity:
package org.exoplatform.social.samples.activityplugin;
import org.exoplatform.social.webui.activity.BaseUIActivity;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.core.lifecycle.UIFormLifecycle;
@ComponentConfig(
lifecycle = UIFormLifecycle.class,
template = "classpath:groovy/social/plugin/space/UISpaceSimpleActivity.gtmpl"
)
public class UISpaceSimpleActivity extends BaseUIActivity {
}
The template UISpaceSimpleActivity.gtmpl should be created under main/resources/groovy/social/plugin/space:
<div>This is a space activity ui component displayed for type "exosocial:spaces"</div>
An activity builder is also needed which will be explained later.
package org.exoplatform.social.samples.activityplugin;
import org.exoplatform.social.core.activity.model.Activity;
import org.exoplatform.social.webui.activity.BaseUIActivity;
import org.exoplatform.social.webui.activity.BaseUIActivityBuilder;
public class SimpleSpaceUIActivityBuilder extends BaseUIActivityBuilder {
@Override
protected void extendUIActivity(BaseUIActivity uiActivity, Activity activity) {
// TODO Auto-generated method stub
}
}
Next, create configuration.xml under conf/portal:
<configuration xmlns="http://www.exoplaform.org/xml/ns/kernel_1_1.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_1.xsd http://www.exoplaform.org/xml/ns/kernel_1_1.xsd">
<external-component-plugins>
<target-component>org.exoplatform.webui.ext.UIExtensionManager</target-component>
<component-plugin>
<name>add.action</name>
<set-method>registerUIExtensionPlugin</set-method>
<type>org.exoplatform.webui.ext.UIExtensionPlugin</type>
<init-params>
<object-param>
<name>Simple Space Activity</name>
<object type="org.exoplatform.social.webui.activity.UIActivityExtension">
<field name="type"><string>org.exoplatform.social.webui.activity.BaseUIActivity</string></field>
<field name="name"><string>exosocial:spaces</string></field>
<field name="component"><string>org.exoplatform.social.samples.activityplugin.UISpaceSimpleActivity</string></field>
<field name="activityBuiderClass"><string>org.exoplatform.social.samples.activityplugin.SimpleSpaceUIActivityBuilder</string></field>
</object>
</object-param>
</init-params>
</component-plugin>
</external-component-plugins>
</configuration>
Note that exosocial:spaces is defined in
<field name="name"><string>exosocial:spaces</string></field>
, its value must match the activity's type you want to display with your UI component.
Build sample project and copy the jar to tomcat/lib. Run Social, create a space and access it. You can see:
space's activity of type "exosocial:spaces" is displayed by default in Social:
With our custom UI component for displaying activity of type: "exosocial:spaces":
1.1.1 Make the custom UI activity display have the look and feel and function like default one.
When displaying an activity, we should make sure the look and feel of the custom UI component is consistent and match other activities and have the functions of like, comments. So, to create the another UI component to display, we call UISpaceLookAndFeelActivity:
package org.exoplatform.social.samples.activityplugin;
import org.exoplatform.social.webui.activity.BaseUIActivity;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.config.annotation.EventConfig;
import org.exoplatform.webui.core.lifecycle.UIFormLifecycle;
@ComponentConfig(
lifecycle = UIFormLifecycle.class,
template = "classpath:groovy/social/plugin/space/UISpaceLookAndFeelActivity.gtmpl",
events = {
@EventConfig(listeners = BaseUIActivity.ToggleDisplayLikesActionListener.class),
@EventConfig(listeners = BaseUIActivity.ToggleDisplayCommentFormActionListener.class),
@EventConfig(listeners = BaseUIActivity.LikeActivityActionListener.class),
@EventConfig(listeners = BaseUIActivity.SetCommentListStatusActionListener.class),
@EventConfig(listeners = BaseUIActivity.PostCommentActionListener.class),
@EventConfig(listeners = BaseUIActivity.DeleteActivityActionListener.class, confirm = "UIActivity.msg.Are_You_Sure_To_Delete_This_Activity"),
@EventConfig(listeners = BaseUIActivity.DeleteCommentActionListener.class, confirm = "UIActivity.msg.Are_You_Sure_To_Delete_This_Comment")
}
)
public class UISpaceLookAndFeelActivity extends BaseUIActivity {
}
Now, create the UISpaceLookAndFeelActivity template by copying the content of UIDefaultActivity.gtmpl to this template file.
You should make needed modifications for this template. We make a small modification here:
<div class="Content"> $activityContentTitle (from custom ui component)<br> </div>
We need to reconfigure configuration.xml:
<configuration xmlns="http://www.exoplaform.org/xml/ns/kernel_1_1.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_1.xsd http://www.exoplaform.org/xml/ns/kernel_1_1.xsd">
<external-component-plugins>
<target-component>org.exoplatform.webui.ext.UIExtensionManager</target-component>
<component-plugin>
<name>add.action</name>
<set-method>registerUIExtensionPlugin</set-method>
<type>org.exoplatform.webui.ext.UIExtensionPlugin</type>
<init-params>
<object-param>
<name>Look And Feel Space Activity</name>
<object type="org.exoplatform.social.webui.activity.UIActivityExtension">
<field name="type"><string>org.exoplatform.social.webui.activity.BaseUIActivity</string></field>
<field name="name"><string>exosocial:spaces</string></field>
<field name="component"><string>org.exoplatform.social.samples.activityplugin.UISpaceLookAndFeelActivity</string></field>
<field name="activityBuiderClass"><string>org.exoplatform.social.samples.activityplugin.SimpleSpaceUIActivityBuilder</string></field>
</object>
</object-param>
</init-params>
</component-plugin>
</external-component-plugins>
</configuration>
Rebuild the sample project, copy jar to tomcat/lib. Rerun the server and see the result:
Currently, we have to copy and paste in the template file. We will have the full control of the UI, but it is not good when there is any change in UIDefaultActivity.
There are 2 components in Social that can be overridden: Space Application Handler & Space Service
Space Application Handler
<component>
<key>org.exoplatform.social.core.space.spi.SpaceApplicationHandler</key>
<type>org.exoplatform.social.core.space.impl.DefaultSpaceApplicationHandler</type>
</component>
Space Service
<component>
<key>org.exoplatform.social.core.space.spi.SpaceService</key>
<type>org.exoplatform.social.core.space.impl.SpaceServiceImpl</type>
<init-params>
<!-- Configure the applications to install in a space -->
<values-param>
<name>space.homeNodeApp</name>
<value>SpaceActivityStreamPortlet</value>
</values-param>
<!-- Configure removable application or not <value>Application:removable</value> -->
<values-param>
<name>space.apps</name>
<value>DashboardPortlet:true</value>
<value>SpaceSettingPortlet:false</value>
<value>MembersPortlet:true</value>
</values-param>
</init-params>
</component>
| Name | Service URL | Description |
|---|---|---|
| ActivitiesRestService | $portalName/social/activities | To provide rest services for activity applications: like/unlike; comment; delete activity. |
API:
| Name | Service URL Endpoint | Description |
|---|---|---|
| destroyActivity | restContextName/social/activities/$activityId/likes/destroy/$identity.$format | To destroy activity and get the json/xml format. |
| showLikes | restContextName/social/activities/$activityId/likes/show.$format | To shows the list of likes by activityId and return the json/xml format. |
| updateLike | restContextName/social/activities/$activityId/likes/update.$format | To update the list of likes by the json/xml format. |
| destroyLike | restContextName/social/activities/$activityId/likes/destroy/$identity.$format | To destroy like by identityId and get the json/xml return format. |
| showComments | restContextName/social/activities/$activityId/likes/show.$format | To show the comment list by the json/xml format. |
| updateComment | restContextName/social/activities/$activityId/likes/update.$format | To update the comment by the json/xml format. |
| destroyComment | restContextName/social/activities/$activityId/comments/destroy/$commentId.$format | To destroy comments and return the json/xml format. |
| Parameter | Expected values |
|---|---|
format | xml/json |
Example:
| Name | Service URL | Description |
|---|---|---|
| AppsRestService | $restContextName/social/apps/show.$format | To provide rest services for the application registry gadget: shows application list |
API:
| Name | Service URL Endpoint | Description |
|---|---|---|
| showApps | $restContextName/social/apps/show.$format | To show applications by the json/xml format. |
| Parameter | Expected values |
|---|---|
format | xml/json |
Example:
| Name | Service URL | Description |
|---|---|---|
| IdentityRestService | $portalName/social/identity/$username/id | To get identityId by the username. |
API:
| Name | Service URL Endpoint | Description | Example |
|---|---|---|---|
| UserId getId | $portalName/social/identity/$username/show.json | To get the identity by username and return by the json format. |
Example:
http://localhost:9090/Socialdemo/social/identity/John/show.json
| Name | Service URL | Description |
|---|---|---|
| LinkshareRestService | $restContextName/social/linkshare | To get information from a provided link. |
API:
| Name | Service URL Endpoint | Description |
|---|---|---|
| getLink | $restContextName/social/linkshare/show.$format | To get the link content by posting with linkShare request as post data |
| Parameter | Expected values |
|---|---|
format | xml/json |
Example:
| Name | Service URL | Description |
|---|---|---|
| SpacesRestService | $portalName/social/spaces | To provide rest services for space gadget to display user's spaces and pending spaces |
API:
| Name | Service URL Endpoint | Description |
|---|---|---|
| showMySpaceList | $restContextName/social/spaces/$userId/mySpaces/show.$format | To show mySpaceList by the json/xml format. |
| showPendingSpaceList | $restContextName/social/spaces/$userId/pendingSpaces/show.$format | To show pendingSpaceList by the json/xml format. |
| Parameter | Expected values |
|---|---|
format | xml/json |
Example:
http://localhost:8080/rest/social/spaces/s08d397dg6/mySpaces/show.xml
| Name | Service URL | Description |
|---|---|---|
| WidgetRestService | {restContextName}/spaces/{portalName} | To provide rest services for creating spaces or getting space's information. |
API:
| Name | Service URL Endpoint | Description |
|---|---|---|
| goToSpace | {restContextName}/spaces/{portalName}/go_to_space | To create (if not existing) or access a space. Two query parameters needed: spaceName and description |
| spaceInfo | {restContextName}/spaces/{portalName}/space_info | To return the HTML page for displaying the information of space. Two query parameters needed: spaceName and description |
| Parameter | Expected values |
|---|---|
portalName | portal/socialdemo |
Example:
http://localhost:8080/rest-socialdemo/spaces/socialdemo/go_to_space?name=Social&description=Social
http://localhost:8080/rest-socialdemo/spaces/socialdemo/space_info?name=Social&description=Social
h3, Activity Stream
eXo Social provides a way to share status updates and activity information for users as well as spaces (aka Activity Streams). With the API, you can customize the activities or publish new ones.
To manipulate activities, you will use the ActivityManager. To get an instance of this class, you will need to use the PortalContainer.
There are two types of activities : activities for a user and activities for a space. The following examples will show you how to create an activity for each type.
Users have activity streams. The code below shows you how to publish a nex activity into the public activity stream of a user.
import org.exoplatform.container.PortalContainer;
import org.exoplatform.social.core.activitystream.ActivityManager;
import org.exoplatform.social.core.activitystream.model.Activity;
import org.exoplatform.social.core.identity.IdentityManager;
import org.exoplatform.social.core.identity.impl.organization.OrganizationIdentityProvider;
import org.exoplatform.social.core.identity.model.Identity;
public void createActivityForUser() {
String username = "zun";
// Get current container
PortalContainer container = PortalContainer.getInstance();
// Get IdentityManager to handle identity operation
IdentityManager identityManager = (IdentityManager) container.getComponentInstance(IdentityManager.class);
// Get ActivityManager to handle activity operation
ActivityManager activityManager = (ActivityManager) container.getComponentInstanceOfType(ActivityManager.class);
// Get existing user or create a new one
try {
Identity userIdentity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, username);
// Create new activity for this user
Activity activity = new Activity();
activity.setUserId(userIdentity.getId());
activity.setTitle("Hello World!");
// Save activity into JCR using ActivityManager
activityManager.saveActivity(activity);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Spaces are also social objects and thus, they own an activity stream. The code below shows you how to publish activity into a space's stream
import org.exoplatform.container.PortalContainer;
import org.exoplatform.social.core.activitystream.ActivityManager;
import org.exoplatform.social.core.activitystream.model.Activity;
import org.exoplatform.social.core.identity.IdentityManager;
import org.exoplatform.social.core.identity.impl.organization.OrganizationIdentityProvider;
import org.exoplatform.social.core.identity.model.Identity;
import org.exoplatform.social.space.Space;
import org.exoplatform.social.space.SpaceException;
import org.exoplatform.social.space.SpaceService;
import org.exoplatform.social.space.impl.SpaceIdentityProvider;
//...
public void createActivityForSpace() {
//make sure a space with name "mySpace" is created.
String spaceName = "mySpace";
String username = "zun";
// Get current container
PortalContainer container = PortalContainer.getInstance();
// Get IdentityManager to handle identity operation
IdentityManager identityManager = (IdentityManager) container.getComponentInstance(IdentityManager.class);
// Get ActivityManager to handle activity operation
ActivityManager activityManager = (ActivityManager) container.getComponentInstanceOfType(ActivityManager.class);
// Get SpaceService to handle space operation
SpaceService spaceService = (SpaceService) container.getComponentInstanceOfType(SpaceService.class);
try {
Space space = spaceService.getSpaceByName(spaceName);
if (space != null) {
// Get space identity via SpaceIdentityProvider
Identity spaceIdentity = identityManager.getOrCreateIdentity(SpaceIdentityProvider.NAME, spaceName);
// Get identity instance of the user who wants to create activity
Identity userIdentity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, username);
// Create new activity for this space
Activity activity = new Activity();
activity.setUserId(userIdentity.getId());
activity.setTitle("An activity for space");
activityManager.saveActivity(spaceIdentity, activity);
}
} catch (SpaceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Activity processor is used for modifying the content of activities before they are responsed and rendered at client's browser. For example, we will create an activity processor for replacing all the texts representing the smile face ":-)" in the activity title by the smiley icons.
Firstly, we will create the SmileyProcessor class by extending the BaseActivityProcessorPlugin
package org.exoplatform.social.core.activitystream;
public class SmileyProcessor extends BaseActivityProcessorPlugin {
public SmileyProcessor(InitParams params) {
super(params);
}
String smiley = "<img src="http://www.tombraider4u.com/pictures/smiley.gif"/>";
public void processActivity(Activity activity) {
String title = activity.getTitle();
activity.setTitle(title.replaceAll(":-
)", smiley));
}
}
And then, we have to register this processor by adding some XML configuration into the project configuration file (configuration.xml)
<component>
<key>org.exoplatform.social.core.activitystream.ActivityManager</key>
<type>org.exoplatform.social.core.activitystream.ActivityManager</type>
<component-plugins>
<component-plugin>
<name>SmileyProcessor</name>
<set-method>addProcessorPlugin</set-method>
<type>org.exoplatform.social.core.activitystrea.SmileyProcessor</type>
<init-params>
<values-param>
<name>priority</name>
<value>1</value>
</values-param>
</init-params>
</component-plugin>
</component-plugins>
</component>
"init-params" contains all the key-value data which a processor will use to initialize. At the above config, priority value indicates the order that this processor will be used. So with '1' value, this processor will be used before all remaining processors with lower priority.
It's really easy to publish an rss feed to a space's activity stream. eXo Social already provides FeedmashJobPlugin for publishing rss feeds. As you can see in project exo.social.extras.feedmash, there are JiraFeedConsumer and HudsonFeedConsumer samples to post eXo Social project's feeds (jira and hudson) to a pre-defined space: exosocial in a specifiportal container: socialdemo as in the configuration file:
<external-component-plugins>
<target-component>org.exoplatform.services.scheduler.JobSchedulerService</target-component>
<component-plugin>
<name>RepubSocialJiraActivityJob</name>
<set-method>addPeriodJob</set-method>
<type>org.exoplatform.social.feedmash.FeedmashJobPlugin</type>
<description/>
<init-params>
<properties-param>
<name>mash.info</name>
<property name="feedURL" value="http://jira.exoplatform.org/plugins/servlet/streams?key=SOC"/>
<property name="categoryMatch" value="resolved|created"/>
<property name="targetActivityStream" value="space:exosocial"/>
<property name="portalContainer" value="socialdemo"/>
</properties-param>
<properties-param>
<name>job.info</name>
<description>save the monitor data periodically</description>
<property name="jobName" value="JIRAFeedConsumer"/>
<property name="groupName" value="Feedmash"/>
<property name="job" value="org.exoplatform.social.feedmash.JiraFeedConsumer"/>
<property name="repeatCount" value="0"/>
<property name="period" value="60000"/>
<property name="startTime" value="+45"/>
<property name="endTime" value=""/>
</properties-param>
</init-params>
</component-plugin>
<component-plugin>
<name>WatchSocialBuildStatus</name>
<set-method>addPeriodJob</set-method>
<type>org.exoplatform.social.feedmash.FeedmashJobPlugin</type>
<description/>
<init-params>
<properties-param>
<name>mash.info</name>
<property name="feedURL" value="http://builder.exoplatform.org/hudson/view/social/job/social-trunk-ci/rssAll"/>
<property name="targetActivityStream" value="space:exosocial"/>
<property name="portalContainer" value="socialdemo"/>
</properties-param>
<properties-param>
<name>job.info</name>
<description>save the monitor data periodically</description>
<property name="jobName" value="HudsonFeedConsumer"/>
<property name="groupName" value="Feedmash"/>
<property name="job" value="org.exoplatform.social.feedmash.HudsonFeedConsumer"/>
<property name="repeatCount" value="0"/>
<property name="period" value="60000"/>
<property name="startTime" value="+100"/>
<property name="endTime" value=""/>
</properties-param>
</init-params>
</component-plugin>
</external-component-plugins>
When running eXo Social, login with http://localhost:8080/socialdemo and create a space named "exosocial". Done, all the feeds from jira and hudson for Social project will be automatically published to exosocial space.
eXo Social provides a way to add profile informations, relationships and connections between users: People. With the eXo People API, profile informations and relationship can be easily managed and customized.
The identity allows to identity uniquely a social object. Social objects can be persons, groups, applications, or whatever you think deserves social interactions like connecting, publishing an activity stream or holding a profile.
Creating your Identity Provider allows you to integrate people outside of your portal (for exemple customers) into your social network without having to create a portal account. You can also use this to populate the profile with data coming from other systems. Here is an example :
class SampleIdentityProvider extends OrganizationIdentityProvider{
public SampleIdentityProvider(OrganizationService organizationService) {
super(organizationService);
}
@Override
public void populateProfile(Profile profile, User user) {
profile.setProperty(Profile.FIRST_NAME, "this is first name");
profile.setProperty(Profile.LAST_NAME, "this is last name");
profile.setProperty(Profile.USERNAME, "this is user name");
profile.setProperty(Profile.URL, "/path/to/profile/");
}
}
In this example, we created a SampleIdentityProvider class extending OrganizationIdentityProvider which is the IdentityProvider used to connect to the portal user's base. In this class, we overrided the populateProfile method and added some dummy data in the profile fields.
The IdentityManager is the service used to manipulate the identity operations like creating, getting, deleting or finding a profile. We can get the IdentityManager via the ExoContainer. The following code will show how to get an IdentityManager instance and create a basic identity instance :
import org.exoplatform.container.ExoContainer; import org.exoplatform.container.ExoContainerContext; import org.exoplatform.social.core.identity.IdentityManager; import org.exoplatform.social.core.identity.impl.organization.OrganizationIdentityProvider; import org.exoplatform.social.core.identity.model.Identity; //...... String containerName = "portal"; String username = "zun"; //get container to get other registered components ExoContainer container = ExoContainerContext.getContainerByName(containerName); //get IdentityManager to handle identity operation IdentityManager identityManager = (IdentityManager) container.getComponentInstanceOfType(IdentityManager.class); //get ActivityManager to handle activity operation ActivityManager activityManager = (ActivityManager) container.getComponentInstanceOfType(ActivityManager.class); //create new user with name Zun Identity userIdentity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, username);
The People API provides some notification interfaces which programmers can implement in order to create their own handlers for notifications like notifications() for profile modifications(ProfileListenerPlugin]) or for relationship changes(RelationshipListenerPlugin]). The following example will guide you through implementing one of these interfaces and show you how to configure this plugin.
We will create the class ProfileLoggerListener. Its tasks is to log all profile modifications of the systems. The abstract class ProfileListenerPlugin provides us the interface to implement this method.
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.social.core.identity.lifecycle.ProfileListenerPlugin;
import org.exoplatform.social.core.identity.spi.ProfileLifeCycleEvent;
public class ProfileLoggerListener extends ProfileListenerPlugin{
private static final Log logger = ExoLogger.getExoLogger(ProfileLoggerListener.class);
@Override
public void avatarUpdated(ProfileLifeCycleEvent event) {
logger.info("@" + event.getUsername() + " profile has updated his basic profile info.");
}
@Override
public void basicInfoUpdated(ProfileLifeCycleEvent event) {
logger.info("@" + event.getUsername() + " profile has updated his basic profile info.");
}
@Override
public void contactSectionUpdated(ProfileLifeCycleEvent event) {
logger.info("@" + event.getUsername() + " profile has updated his contact info.");
}
@Override
public void experienceSectionUpdated(ProfileLifeCycleEvent event) {
logger.info("@" + event.getUsername() + " profile has an updated experience section.");
}
@Override
public void headerSectionUpdated(ProfileLifeCycleEvent event) {
logger.info("@" + event.getUsername() + " has updated his header info.");
}
}
After creating the ProfileLoggerListener class, we have to add some configurations for this class to the configuration.xml :
<external-component-plugins>
<target-component>org.exoplatform.social.core.identity.IdentityManager</target-component>
<component-plugin>
<name>ProfileLoggerListener</name>
<set-method>addProfileListener</set-method>
<type>path.to.ProfileLoggerListener</type>
</component-plugin>
</external-component-plugins>
Similarly, you can apply the above steps to implement the RelationshipListenerPlugin for relationship notifications.
Relationship is the bridge between two identities in eXo Social. There are many types of relationships defined in the Relationship class. With these types, a user can invite another user, confirm invitations or remove relationship.
The following code will show how to invite a user to connect to another :
import org.exoplatform.container.ExoContainer;
import org.exoplatform.container.ExoContainerContext;
import org.exoplatform.social.core.identity.IdentityManager;
import org.exoplatform.social.core.identity.impl.organization.OrganizationIdentityProvider;
import org.exoplatform.social.core.identity.model.Identity;
import org.exoplatform.social.core.relationship.Relationship;
import org.exoplatform.social.core.relationship.RelationshipManager;
public void inviteUser() throws Exception {
String containerName = "portal";
ExoContainer container = ExoContainerContext.getContainerByName(containerName);
IdentityManager identityManager = (IdentityManager) container.getComponentInstanceOfType(IdentityManager.class);
Identity invitedIdentity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, "Hoat");
String invitedUserId = invitedIdentity.getId();
String currUserId = "Zun";
Identity currentIdentity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, currUserId);
RelationshipManager relationshipManager = (RelationshipManager) container.getComponentInstanceOfType(RelationshipManager.class);
Relationship relationship = relationshipManager.invite( currentIdentity, invitedIdentity);
}
Let's take a look at relationship Listener(RelationshipListenerPlugin). The following example will show you how to implement one of these interfaces and how to configure this plugin. The following step is similar to the Profile notifications implementation.
import org.exoplatform.social.core.relationship.Relationship;
import org.exoplatform.social.core.relationship.lifecycle.RelationshipListenerPlugin;
import org.exoplatform.social.relationship.spi.RelationshipEvent;
public class RelationshipLoggerListener extends RelationshipListenerPlugin{
private static final Log logger = ExoLogger.getExoLogger(RelationshipLoggerListener.class);
@Override
public void confirmed(RelationshipEvent event) {
String[] names = getUserNamesFromEvent(event);
logger.info(names[0] +" confirmed the invitation of "+ names[1]);
}
@Override
public void ignored(RelationshipEvent event) {
String[] names = getUserNamesFromEvent(event);
logger.info(names[0] +" ignored the invitation of "+ names[1]);
}
@Override
public void removed(RelationshipEvent event) {
String[] names = getUserNamesFromEvent(event);
logger.info(names[0] +" removed the relationship with "+ names[1]);
}
private String[] getUserNamesFromEvent(RelationshipEvent event){
Relationship relationship = event.getPayload();
Identity id1 = relationship.getIdentity1();
Identity id2 = relationship.getIdentity2();
String user1 = "@" + id1.getRemoteId();
String user2 = "@" + id2.getRemoteId();
return new String[]{user1, user2 };
}
}
After creating the RelationshipLoggerListener class, we have to add some configurations for this class to the configuration.xml :
<external-component-plugins>
<target-component>org.exoplatform.social.core.relationship.RelationshipManager</target-component>
<component-plugin>
<name>RelationshipLoggerListener</name>
<set-method>addListenerPlugin</set-method>
<type>classpath.of.your.RelationshipLoggerListener</type>
</component-plugin>
</external-component-plugins>
eXo Social provides a way to create groups and to share data and applications: the space. A space has it's own activity stream in which applications or members can publish information. In each space, members share applications and an openSocial dashboard.
To manipulate the spaces, you will use the SpaceService. To get an instance of this class, you will need to get current PortalContainer instance.
The following example shows how to create a space:
package org.exoplatform.social.sample;
import org.exoplatform.container.PortalContainer;
import org.exoplatform.social.application.impl.DefaultSpaceApplicationHandler;
import org.exoplatform.social.space.Space;
import org.exoplatform.social.space.SpaceException;
import org.exoplatform.social.space.SpaceService;
public class SpaceCreationSample {
public void createSpace() throws SpaceException {
String spaceName = "mySpace";
String creator = "jeremi";
PortalContainer container = PortalContainer.getInstance();
SpaceService spaceService = (SpaceService) container.getComponentInstanceOfType(SpaceService.class);
// We verify if there is no space already created
Space space = spaceService.getSpaceByName(spaceName);
if (space == null) {
space = new Space();
space.setName(spaceName);
space.setRegistration(Space.OPEN);
space.setDescription("space description");
//DefaultSpaceApplicationHander is the default implementation of SpaceApplicationHandler. You can create your own by extending SpaceApplicationHandler. The default type is "classic" (DefaultSpaceApplicationHandler.NAME = clasic)
space.setType(DefaultSpaceApplicationHandler.NAME);
//We create the space
space = spaceService.createSpace(space, creator);
//We initialize the applications
spaceService.initApp(space);
}
}
}
We can add a portlet or gadget applications into spaces. Once added, all members of the space can use that application. The following code shows how to add an application into a space :
public void addApplicationToSpace() throws SpaceException {
//Your portlet name
String appId = "AnyGadgetOrAnyPortletName";
String spaceId = "zunSpace";
//get container to get other registered components
PortalContainer container = PortalContainer.getInstance();
//get space service for installing operations
SpaceService spaceService = (SpaceService) container.getComponentInstanceOfType(SpaceService.class);
//install application for the space
spaceService.installApplication(spaceId, appId);
//we must activate installed application to be able to use it
spaceService.activateApplication(spaceId, appId);
}
appId is the portlet or gadget name as defined in portlet.xml or gadget.xml in the web-app. With eXo Social, we can find it in social-portlet.war and social.war.
The SpaceService allows you to manage the spaces' members.Here is how you would add a now member to a space:
String spaceName = "mySpace";
PortalContainer container = PortalContainer.getInstance();
SpaceService spaceService = (SpaceService) container.getComponentInstanceOfType(SpaceService.class);
Space space = service.getSpaceByName(spaceName);
if (space != null) {
spaceService.addMember(space, "mary");
}
To receive notifications of what is happening in spaces, you need to extend SpaceListenerPlugin and register it. Every method takes a SpaceLifeCycleEvent object as parameter that contain the information about the event and it's context.
The events available are:
spaceCreated: this event is called right after space is created successfully with its applications.
spaceRemoved: this event is called right after a space is removed: application's removed, its group and group navigation is removed
applicationAdded: this event is called right after an application is added (installed) to a space
applicationActivated: this event is called right after an application is activated.
applicationDeactivated: this event is called right after an application is deactivated.
applicationRemoved: this event is called right after an application is removed from a space.
joined: this event is called right after a user joins a space.
left: this event is called right after a space member leaves its space.
grantedLead: this event is called right after a user is grated space's manager role.
revokedLead: this event is called right after a space's manager is revoked his role to be a space member.
import org.exoplatform.social.space.lifecycle.SpaceListenerPlugin;
public class MySpaceListenerPlugin extends SpaceListenerPlugin {
...
}
As an example, see the SpaceActivityPublisher that publishes an activity based on an event that happened in a space.
To register your listener, hook it to the SpaceService like this :
<external-component-plugins>
<target-component>org.exoplatform.social.space.SpaceService</target-component>
<component-plugin>
<name>SpaceActivityPublisher</name>
<set-method>addSpaceListener</set-method>
<type>org.mycompany.MySpaceListenerPlugin</type>
</component-plugin>
</external-component-plugins>
eXo Social is implementing the OpenSocial standard. So you can integrate OpenSocial Gadget in your dashboard and use the RPC or REST API to access to the social data.
Gadgets are web-based software components based on HTML, CSS, and JavaScript. They allow developers to easily write useful web applications that work anywhere on the web without modification. To know more, we suggest some links for detail information :
OpenSocial Core Gadget Specification 10
After getting acquainted with Gadget concept, we enter into the detail on how to create an opensocial gadget. However, the tutorials are done greatly in Opensocial official site so we refer you to read these tutorials at that website
We only note that in Opensocial gadgets only work in the dashboard in eXo Social.
As we have said above, eXo Social is implementing the OpenSocial standard. So every eXo Social implementations apply the Opensocial Specification generally or Apache Shindig specifically. Therefore, eXo Social uses and extends Apache Shindig APIs to compatible with the common Opensocial APIs which is supported by other big social networks like Ning, Hi5, Orkut ...
To get more detail about Supported APIs, we refer you to read Opensocial Specs
If your eXo social server is running on http://localhost:8080/ the address of the API will be:
REST API: http://localhost:8080/social/social/rest
RPC API: http://localhost:8080/social/social/rpc
To learn what you can do with this APIs, have a look at the specification. If you are developing in Java, you can use the opensocial-java-client
If you are using opensocial, there is good chance you are going to need to configure the oAuth authentication. To do this, you need to edit the configuration to add you oAuth key.
Edit the file: gatein/conf/portal/portal/configuration.xml and add this component:
<component>
<key>org.exoplatform.social.opensocial.oauth.ServiceProviderStore</key>
<type>org.exoplatform.social.opensocial.oauth.ServiceProviderStore</type>
<init-params>
<properties-param>
<name>grails-book-flow</name>
<description>consmer key and secret for sample oauth provider. </description>
<property name="consumerKey" value="YOUR_KEY_HERE" />
<property name="sharedSecret" value="YOUR_SECRET_KEY_HERE" />
</properties-param>
</init-params>
</component>
The consumerKey and sharedSecret are the key that need to be shared with the application that is doing the request.
eXo Social added this functionality that is not available in the standard opensocial API. You can publish activities into a space using the opensocial API.
To do this, instead of publishing your activity to the group @self as usual, publish it to the group "space:spaceID" or "space:spaceName".
Using the opensocial java library and groovy, your code will look like this:
def client = getOpenSocialClient()
//we create our new activity
Activity activity = new Activity()
activity.title = "BookFlow Purchase"
activity.body = "xx puchased the book xxx"
//We prepare the request that will create the activity
Request request = ActivitiesService.createActivity(activity);
//We specify that the creation of this new activity is for the space bookflow
request.groupId = "space:bookflow";
client.send(request);
As you can see in this example, we set the groupId to "space:bookflow", bookflow being the name of our space.
eXo Social is implementing the OpenSocial standard. So you can integrate OpenSocial Gadget in your dashboard and use the RPC or REST API to access to the social data.
Gadgets are web-based software components based on HTML, CSS, and JavaScript. They allow developers to easily write useful web applications that work anywhere on the web without modification. To know more, we suggest some links for detail information :
OpenSocial Core Gadget Specification 10
After getting acquainted with Gadget concept, we enter into the detail on how to create an opensocial gadget. However, the tutorials are done greatly in Opensocial official site so we refer you to read these tutorials at that website
We only note that in Opensocial gadgets only work in the dashboard in eXo Social.
As we have said above, eXo Social is implementing the OpenSocial standard. So every eXo Social implementations apply the Opensocial Specification generally or Apache Shindig specifically. Therefore, eXo Social uses and extends Apache Shindig APIs to compatible with the common Opensocial APIs which is supported by other big social networks like Ning, Hi5, Orkut ...
To get more detail about Supported APIs, we refer you to read Opensocial Specs
If your eXo social server is running on http://localhost:8080/ the address of the API will be:
REST API: http://localhost:8080/social/social/rest
RPC API: http://localhost:8080/social/social/rpc
To learn what you can do with this APIs, have a look at the specification. If you are developing in Java, you can use the opensocial-java-client
If you are using opensocial, there is good chance you are going to need to configure the oAuth authentication. To do this, you need to edit the configuration to add you oAuth key.
Edit the file: gatein/conf/portal/portal/configuration.xml and add this component:
<component>
<key>org.exoplatform.social.opensocial.oauth.ServiceProviderStore</key>
<type>org.exoplatform.social.opensocial.oauth.ServiceProviderStore</type>
<init-params>
<properties-param>
<name>grails-book-flow</name>
<description>consmer key and secret for sample oauth provider. </description>
<property name="consumerKey" value="YOUR_KEY_HERE" />
<property name="sharedSecret" value="YOUR_SECRET_KEY_HERE" />
</properties-param>
</init-params>
</component>
The consumerKey and sharedSecret are the key that need to be shared with the application that is doing the request.
eXo Social added this functionality that is not available in the standard opensocial API. You can publish activities into a space using the opensocial API.
To do this, instead of publishing your activity to the group @self as usual, publish it to the group "space:spaceID" or "space:spaceName".
Using the opensocial java library and groovy, your code will look like this:
def client = getOpenSocialClient()
//we create our new activity
Activity activity = new Activity()
activity.title = "BookFlow Purchase"
activity.body = "xx puchased the book xxx"
//We prepare the request that will create the activity
Request request = ActivitiesService.createActivity(activity);
//We specify that the creation of this new activity is for the space bookflow
request.groupId = "space:bookflow";
client.send(request);
As you can see in this example, we set the groupId to "space:bookflow", bookflow being the name of our space.
The eXo Social widget enables developers to add capabilities of eXo Social to external applications. Since the widget is hosted on your eXo Social server, it can display personalized information. An activity stream of the most recent user actions will display to the group's members.
There are two options of the eXo Social widget that provide different levels of integration and information.
The basic version of this widget is an iFrame. The more advanced version is a button you can insert in a page; this will display a small pop-up with information about the space.
To insert the basic version, you need to have an iFrame to insert on your site.
<iframe scrolling="no" height="180" frameborder="no" width="220" src="http://URL_OF_YOUR_EXO_INSTALLATION.COM/rest/private/spaces/portal/space_info?spaceName=NAME_OF_YOUR_SPACE&description=DESCRIPTION_OF_THE_SPACE"></iframe>
To install this version in your application, replace all the uppercase text below:
URLOFYOUREXOINSTALLATION.COM - this is the URL of your eXo Social installation. If you are testing on your local computer, the URL may be localhost:8080_
NAMEOFYOURSPACE - this is the title of your space in eXo Social. In the URL, it is necessary to avoid special characters. For the space name, you can only use alphanumeric characters and "", ".", "-" or ". "
DESCRIPTIONOFTHESPACE - this will be displayed in the list of spaces.
To install an advanced version of the widget, you need to insert a code snippet in your page. This includes some HTMLs plus some JavaScripts. The necessary CSS will be added dynamically.
Next, insert the following code at the position you want the button to be displayed:
<div class="exoSpacesContainer"><a href="javascript:void(0);" id="exoSpacesLink" class="exoSpacesLink" target="_blank">Space</a></div>
<script src="/socialWidgetResources/javascript/space.js"></script>
<script>spaces.createPopup("exoSpacesLink", "MyAppName - my social object", "my cool description");</script>
The important function here is:
spaces.createPopup(link, spaceName, description)
link: link is the ID or the HTMLElement where the pop-up will be placed. If you copy and paste the code snippet provided above, you donot need to change this value.
spaceName: This is the name of space. It is also used to identify the space. We recommend you use the following format: "MyAppName - my social object"
description: This is the description of your space that will be displayed within eXo Spaces. It is used when a new space is created.
serverURL (Default: "http://127.0.0.1:8080"): The address of your eXo installation. To change it, use spaces.setServerURL(...);
spaceServicePath (Default: "/rest/private/spaces/"): The path to the spaces service. It is rare you have to change it; but if needed, use spaces.setSpaceServicePath(...);
portalName (Default: "socialdemo"): The name of portal you are using. To change it, use spaces.setPortalName(...);
If you want to change any part of this configuration, the best way is to change before creating the pop-up. For example:
<div class="exoSpacesContainer"><a href="#" id="exoSpacesLink" class="exoSpacesLink" target="_blank">Space</a></div>
<script src="/socialWidgetResources/javascript/space.js"></script>
<script>
spaces.setServerURL("http://192.168.2.100:8080");
spaces.createPopup("exoSpacesLink", "My cool new space", "my cool description");
</script>
You can see an example of integration at: http://localhost:8080/socialWidgetResources/test.html
All references for Opensocial Javascript APIs can be viewed here