Google Gadget and OpenSocial Integration

Google Gadget and OpenSocial Integration (GSoC 2009)

Abstract

Gadgets integration with XWiki will allow users to quickly add any gadget from Google's Gadget Directory to any wiki page or the side panels. Gadgets offer the most diverse functionalities and will benefit many of the unanticipated user needs.

The OpenSocial Integration will add a more social dimension to XWiki by hosting OpenSocial apps, thus becoming the first wiki OpenSocial Container. Anyone will be able to install XWiki and instantly create their own social collaborative orientated network.

Oct 29 2009

Drag&Drop iGoogle like Dashboard

I've been playing around with Smartclient to create an iGoogle like Dashboard with drag&drop windows for the Apps. You can play with it here:

App Dashboard

Aug 24 2009

Files listing

Changes on xwiki-web-standard module (patch)

These changes comprise new velocity files, Shindig JS files, Shindig container configurations, modifications to module's web.xml and pom.xml files.

in standard/src/main/webapps/templates:

Additional Velocity files:

  • addapplication.vm - installs an application from the directory for a user; the result is a document with an OpenSocialApplication.ApplicationClass attached to it, in the Space OpenSocialApplication; also specific rights are set for the document: all to self, some to admin, only view to others
  • getuserprefs.vm - returns a JSON with all the OpenSocial User Preferences set/saved by a specific gadget/application; the UserPrefs are key-value pairs, and are stored as OpenSocial.UserPrefClass objects attached to installed application pages
  • saveuserprefs.vm - saves new User Prefs for a application and user
  • addfriend.vm - adds a friend for a user; friends are XWiki.FriendClass objects attached to a user's profile page. XWiki.FriendClass objects have a property called friendName wich keeps the document full name of the user friend
  • getuserfriends.vm - returns the friends of a user
  • deletefriend.vm - deletes a friend

in standard/src/main/webapps/resources/xwiki/opensocial:

Added javascript and css files necessary for the Shindig client container:

  • gadgets.js
  • rpc.js
  • util.js
  • json.js
  • gadgets.css

in standard/src/main/webapps/WEB-INF:

Modified web.xml to include all shindig servlet mappings and necessary Guice modules:

  • Shindig Guice modules:
<!-- Shidig Guice modules -->
  <context-param>
    <param-name>guice-modules</param-name>
    <param-value>
      org.apache.shindig.common.PropertiesModule:
      org.apache.shindig.gadgets.DefaultGuiceModule:
      org.apache.shindig.gadgets.oauth.OAuthModule:
      org.apache.shindig.common.cache.ehcache.EhCacheModule:
      org.xwiki.opensocial.social.XWSocialModule
    </param-value>
  </context-param>

  • Shindig filters:
<!-- Shindig filters -->
  <filter>
    <filter-name>authFilter</filter-name>
    <filter-class>org.apache.shindig.auth.AuthenticationServletFilter</filter-class>
  </filter>

  • Shindig filter mappings:
<!-- Shindig filter mappings -->
  <filter-mapping>
    <filter-name>authFilter</filter-name>
    <url-pattern>/social/*</url-pattern>
  </filter-mapping>

<filter-mapping> <filter-name>authFilter</filter-name> <url-pattern>/gadgets/ifr</url-pattern> </filter-mapping>

<filter-mapping> <filter-name>authFilter</filter-name> <url-pattern>/gadgets/makeRequest</url-pattern> </filter-mapping>

<filter-mapping> <filter-name>authFilter</filter-name> <url-pattern>/gadgets/api/rpc/*</url-pattern> </filter-mapping>

<filter-mapping> <filter-name>authFilter</filter-name> <url-pattern>/gadgets/api/rest/*</url-pattern> </filter-mapping>

  • Shindig Guice listener:
<!-- Shindig Guice listener -->
  <listener>
    <listener-class>org.apache.shindig.common.servlet.GuiceServletContextListener</listener-class>
  </listener>

  • Shindig Servlets:
<!-- Render a Gadget -->
  <servlet>
    <servlet-name>xml-to-html</servlet-name>
    <servlet-class>
      org.apache.shindig.gadgets.servlet.GadgetRenderingServlet
    </servlet-class>
  </servlet>

<!-- Proxy --> <servlet> <servlet-name>proxy</servlet-name> <servlet-class> org.apache.shindig.gadgets.servlet.ProxyServlet </servlet-class> </servlet>

<!-- makeRequest --> <servlet> <servlet-name>makeRequest</servlet-name> <servlet-class> org.apache.shindig.gadgets.servlet.MakeRequestServlet </servlet-class> </servlet>

<servlet> <servlet-name>concat</servlet-name> <servlet-class> org.apache.shindig.gadgets.servlet.ConcatProxyServlet </servlet-class> </servlet>

<!-- OAuth callback --> <servlet> <servlet-name>oauthCallback</servlet-name> <servlet-class> org.apache.shindig.gadgets.servlet.OAuthCallbackServlet </servlet-class> </servlet>

<!-- Metadata RPC --> <servlet> <servlet-name>metadata</servlet-name> <servlet-class> org.apache.shindig.gadgets.servlet.RpcServlet </servlet-class> </servlet>

<!-- javascript serving --> <servlet> <servlet-name>js</servlet-name> <servlet-class>org.apache.shindig.gadgets.servlet.JsServlet</servlet-class> </servlet>

<!-- Serve social REST api --> <servlet> <servlet-name>socialRestapiServlet</servlet-name> <servlet-class> org.apache.shindig.protocol.DataServiceServlet </servlet-class> <init-param> <param-name>handlers</param-name> <param-value>org.apache.shindig.social.handlers</param-value> </init-param> </servlet>

<!-- Serve social RPC api --> <servlet> <servlet-name>socialJsonRpcServlet</servlet-name> <servlet-class> org.xwiki.opensocial.social.XWikiShindigServlet </servlet-class> <init-param> <param-name>handlers</param-name> <param-value>org.apache.shindig.social.handlers</param-value> </init-param> </servlet>

<!-- Serve gadgets RPC api --> <servlet> <servlet-name>gadgetsJsonRpcServlet</servlet-name> <servlet-class> org.apache.shindig.protocol.JsonRpcServlet </servlet-class> <init-param> <param-name>handlers</param-name> <param-value>org.apache.shindig.gadgets.handlers</param-value> </init-param> </servlet>

<!-- Serve gadgets REST api --> <servlet> <servlet-name>gadgetsRestapiServlet</servlet-name> <servlet-class> org.apache.shindig.protocol.DataServiceServlet </servlet-class> <init-param> <param-name>handlers</param-name> <param-value>org.apache.shindig.gadgets.handlers</param-value> </init-param> </servlet>

  • Shindig Servlet mappings:
<!-- Shindig servlet mappings -->
  <servlet-mapping>
    <servlet-name>js</servlet-name>
    <url-pattern>/gadgets/js/*</url-pattern>
  </servlet-mapping>

<servlet-mapping> <servlet-name>proxy</servlet-name> <url-pattern>/gadgets/proxy/*</url-pattern> </servlet-mapping>

<servlet-mapping> <servlet-name>makeRequest</servlet-name> <url-pattern>/gadgets/makeRequest</url-pattern> </servlet-mapping>

<servlet-mapping> <servlet-name>gadgetsJsonRpcServlet</servlet-name> <url-pattern>/gadgets/api/rpc/*</url-pattern> </servlet-mapping>

<servlet-mapping> <servlet-name>gadgetsRestapiServlet</servlet-name> <url-pattern>/gadgets/api/rest/*</url-pattern> </servlet-mapping>

<servlet-mapping> <servlet-name>concat</servlet-name> <url-pattern>/gadgets/concat</url-pattern> </servlet-mapping>

<servlet-mapping> <servlet-name>oauthCallback</servlet-name> <url-pattern>/gadgets/oauthcallback</url-pattern> </servlet-mapping>

<servlet-mapping> <servlet-name>xml-to-html</servlet-name> <url-pattern>/gadgets/ifr</url-pattern> </servlet-mapping>

<servlet-mapping> <servlet-name>metadata</servlet-name> <url-pattern>/gadgets/metadata</url-pattern> </servlet-mapping>

<servlet-mapping> <servlet-name>socialRestapiServlet</servlet-name> <url-pattern>/social/rest/*</url-pattern> </servlet-mapping>

<servlet-mapping> <servlet-name>socialJsonRpcServlet</servlet-name> <url-pattern>/social/rpc/*</url-pattern> </servlet-mapping>

in standard/src/main/webapps/WEB-INF/classes:

Added container/default/container.js and shindig.properties - shindig container configurations files. I modified the base URLs for the services provided by Shindig, so they all contain /xwiki/.
For example, http://%host%/gadgets/api/rpc becomes http://%host%/xwiki/gadgets/api/rpc.
I placed the 2 files in the classpath, as they required modifications from the original files.

in standard/src/main/webapps/resources/icons/silk:

  • os_app.js - added an icon for the gadgets (used in css)

in standard:

Modified pom.xml, to include as a dependency xwiki-social-opensocial module

<!-- The OpenSocial module -->
    <dependency>
      <groupId>org.xwiki.platform</groupId>
      <artifactId>xwiki-social-opensocial</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>

XClasses and documents created (.XAR Application)

  • OpenSocial.AppDataClass - Application data created by applications for a specific user. Objects of this type are saved as attachments on installed application pages (pages containing objects of type OpenSocialApplication.ApplicationClass); App data is saved in the form of key-value pairs
  • OpenSocial.AppDataClassSheet - default content
  • OpenSocial.AppDataClassTemplate - default content
  • OpenSocial.Dashboard - Displays applications all installed applications for the logged in user in the profile/default view form; The page script includes shindig JS files, retrieves all apps of interest, adds them to the container, and renders them:
$xwiki.jsfx.use("js/xwiki/opensocial/json.js")
$xwiki.jsfx.use("js/xwiki/opensocial/rpc.js")
$xwiki.jsfx.use("js/xwiki/opensocial/cookies.js")
$xwiki.jsfx.use("js/xwiki/opensocial/util.js")
$xwiki.jsfx.use("js/xwiki/opensocial/gadgets.js")
$xwiki.ssfx.use("js/xwiki/opensocial/gadgets.css")
$xwiki.jsx.use("OpenSocial.Dashboard")
…
## Get all viewer apps
#set($sql = ", BaseObject obj, StringProperty prop where doc.fullName=obj.name and obj.className='OpenSocialApplication.ApplicationClass' and prop.id.id=obj.id and prop.name='userId' and prop.value='$context.user' order by doc.date desc")
…
<div id="layout-root" class="gadgets-layout-root"></div><script>
   … 
  document.observe('xwiki:dom:loaded', function() { init(myapps); renderGadgets(); });
</script>

There is a JSX object attached to the page, which defines a class XWikiDashboardGadget extending gadgets.IfrGadget. The new class adds functionalities to default IfrGadget, like gadget maximize handler (to canvas view), changes the content of the gadget box title and adds new fields (e.g. fullAppUrl). The other class gadgets.XWikiUserPrefStore (extends gadgets.UserPrefStore) handles persistent data storage for the User Preferences of each application and user. The UserPrefs are saved as OpenSocial.UserPrefClass objects.

/** XWiki Ifr Dashboard Gadget **/
XWikiDashboardGadget = function(opt_params) {
  gadgets.IfrGadget.call(this, opt_params);
};

XWikiDashboardGadget.inherits(gadgets.IfrGadget);

XWikiDashboardGadget.prototype.handleMaximize = function() { window.location = this.fullAppUrl; };

XWikiDashboardGadget.prototype.getTitleBarContent = function(continuation) { continuation('<div id="' + this.cssClassTitleBar + '-' + this.id + '" class="' + this.cssClassTitleBar + '"><span id="' + this.getIframeId() + '_title" class="' + this.cssClassTitle + '">' + (this.title ? this.title : 'Title') + '</span> | <span class="' + this.cssClassTitleButtonBar + '"><a href="#" onclick="gadgets.container.getGadget(' + this.id + ').handleOpenUserPrefsDialog();return false;" class="' + this.cssClassTitleButton + '">settings</a> <a href="#" onclick="gadgets.container.getGadget(' + this.id + ').handleToggle();return false;" class="' + this.cssClassTitleButton + '">toggle</a> <a href="#" onclick="gadgets.container.getGadget(' + this.id + ').handleMaximize();return false;" class="' + this.cssClassTitleButton + '">see full app</a></span></div>'); };

gadgets.container.gadgetClass = XWikiDashboardGadget;

/** XWiki persistent UserPrefStore **/ gadgets.XWikiUserPrefStore = function() { gadgets.UserPrefStore.call(this); };

gadgets.XWikiUserPrefStore.inherits(gadgets.UserPrefStore);

gadgets.XWikiUserPrefStore.prototype.savePrefs = function(gadget) { var pairs = []; for (var name in gadget.getUserPrefs()) { var value = gadget.getUserPref(name); var pair = encodeURIComponent(name) + '=' + encodeURIComponent(value); pairs.push(pair); } var params = pairs.join('&'); // store user prefs parameters var url = gadget.fullAppUrl + "?xpage=saveuserprefs" + "&" + "params=" + encodeURIComponent(params); new Ajax.Request(url, { method: 'get', onSuccess: savePrefsAjaxSuccess }); };

gadgets.XWikiUserPrefStore.prototype.getPrefs = function(gadget) { var userPrefs = {}; var url = gadget.fullAppUrl + "?xpage=getuserprefs"; new Ajax.Request(url, { method: 'get', onSuccess: getPrefsAjaxSuccess }); return userPrefs; };

gadgets.Container.prototype.userPrefStore = new gadgets.XWikiUserPrefStore();

/** Initialize XWiki Dashboard Container **/ function init(apps) { gadgets.container.layoutManager = new gadgets.FloatLeftLayoutManager('layout-root'); for (var specUrl in apps) { gadgets.container.addGadget(gadgets.container.createGadget({specUrl: specUrl, title: apps[specUrl].title, fullAppUrl: apps[specUrl].fullAppUrl})); } };

/** Render all gadgets on Dashboard **/ function renderGadgets() { gadgets.container.renderGadgets(); };

Links to Edit applications page and Directory (to Add more apps) are also present.

  • OpenSocial.Stylesheet - a bit of CSS
  • OpenSocial.TestingGadgetsSource - used to attach gadgets XML files to the page. Their URLs can be used when adding applications to the Directory
  • OpenSocial.UserPrefClass - stores User Preferences for each application and user in the form of key-value pais
  • OpenSocial.UserPrefClassSheet - default content
  • OpenSocial.UserPrefClassTemplate - default content
  • OpenSocialAppInfo.AppInfoClass - Defines an application from the Directory; contains fields like: URL to Gadget XML definition file, name, description (should also contain image and icon URLs, authors, etc.)
  • OpenSocialAppInfo.AppInfoClassSheet - Displays an application from the Directory. You have links to install the application for yourself, or to manage/delete if you already have it installed; You can also see the Friends which have the same application installed.
Fetching friends with the same app (big sql follows :) ):
#set($appId = $doc.fullName)
#set($sql = "select fnp.value from XWikiDocument adoc, XWikiDocument udoc, BaseObject fo, BaseObject ao, StringProperty fnp, StringProperty uidp, StringProperty aidp where adoc.fullName=ao.name and udoc.fullName=fo.name and udoc.fullName='$context.user' and ao.className='OpenSocialApplication.ApplicationClass' and fo.className='XWiki.FriendClass' and uidp.id.id=ao.id and aidp.id.id=ao.id and fnp.id.id=fo.id and uidp.name='userId' and aidp.name='appId' and aidp.value='$appId' and fnp.name='friendName' and fnp.value=uidp.value")
#set($results = $xwiki.search($sql))

  • OpenSocialAppInfo.AppInfoClassTemplate - default content
  • OpenSocialAppInfo.WebHome - Application Directory. Lists all apps in the Directory and provides a form for adding new ones.
  • OpenScocialApplication.ApplicationClass - Defines an installed application; the two properties name the application id (addId) - document full name for the application in the directory (a document with OpenSocialAppInfo.AppInfoClass object attached), and the user id (userId) - user document full name
  • OpenScocialApplication.ApplicationClassSheet - Renders the application in Canvas view format. Like OpenSocial.Dashboard, includes the Shindig JS files, but renders only 1 gadget this time, and in the canvas format. This gadget is of type XWikiCanvasGadget (extends gadgets.IfrGadget) and is defined in a JSX object attached to the document.
XWikiCanvasGadget = function(opt_params) {
  gadgets.IfrGadget.call(this, opt_params);
};

XWikiCanvasGadget.inherits(gadgets.IfrGadget);

XWikiCanvasGadget.prototype.getTitleBarContent = function(continuation) { continuation('');};

XWikiCanvasGadget.prototype.getUserPrefsDialogContent = function(continuation) { continuation('');};

gadgets.container.gadgetClass = XWikiCanvasGadget;

function canvasRenderGadget(specUrlVal) { var app = gadgets.container.createGadget({specUrl: specUrlVal, width: "100%", height: "600"}); gadgets.container.setView("canvas"); gadgets.container.addGadget(app); gadgets.container.layoutManager.setGadgetChromeIds(['gadget-chrome']); gadgets.container.renderGadget(app); }

  • OpenScocialApplication.ApplicationClassTemplate - default content
  • OpenScocialApplication.MyApps - Lists all installed applications, with buttons to manage/remove. Also there is a button to Add more apps.
  • Panels.MyApps - Panel, displays the newest installed apps (max 5) for the currently logged in user; links to dashboard, edit apps, directory
  • Panels.MyFriends - Panel, displays the friends (max 4) with profile picture of the currently logged in user; links to Profile page for whole list
  • Panels.Navigation - Added the 2 panels
  • XWiki.FriendClass - A friend; objects of this are attached to user profiles; they have a single property friendName, which contains the friends' document full name
  • XWiki.FriendClassSheet - Uses a livetable to display/add friends
  • XWiki.FriendClassTemplate - default content
  • XWiki.MyResources
  • XWiki.XWikiPreferences - Modified
  • XWiki.XWikiUserSheet - Modified to include listing of friends (XWiki.FriendClassSheet) and list applications

xwiki-social-opensocial module

Implements Shindig services and connects Shindig to XWiki's datastore. The implementation is based on the DocumentAccessBridge component, which provides access to data on XWiki.

The implementation is still in an incipient phase, as the registration to XWiki's Component Manager didn't work out as expected. The conflict emerges from the fact that the 4 services (PersonServiceXW, ActivityServiceXW, MessageServiceXW, PersonServiceXW etc.) are instantiated both with Guice for Sindig and by XWiki's Component Manager. For more information, see discussion here: http://markmail.org/thread/zxlnu7q67fxzrjmk

Module details

Packages and Classes:

  • org.xwiki.opensocial.social
    • XWSocialModule.java
  • org.xwiki.opensocial.social.model
    • AddressXW.java
    • NameXW.java
    • PersonXW.java
    • PersonXWComparator.java
  • org.xwiki.opensocial.social.oauth
    • SocialServiceComponent.java - XWiki Component Role, implemented by ActivityServiceXW, AppDataServiceXW, MessageServiceXW, PersonServiceXW in order to gain access to the DocumentAccessBridge component and fetch/add/delete data
  • org.xwiki.opensocial.social.spi.internal
    • ActivityServiceXW.java
    • AppDataServiceXW.java
    • MessageServiceXW.java
    • PersonServiceXW.java - Implements Shindig's PersonService, which fetches people from the datastore

Screenshots

My Friends Panel

Displays maximum 4 friends of the currently logged in user
Picture17.png

My Apps Panel

Displays most recent 5 installed applications by the currently logged in user
Picture18.png

Edit Applications

You can manage your installed applications: edit app settings or remove
Picture19.png

Application Directory

You can browse the directory and install any application available. If not, you can add new applications to the directory by providing the XML URL for the Application/Gadget
Picture20.png

Application Info Page

Presents information about a certain Gadget/Application in the Directory. You can install it (if you don't already have it installed or edit/remove it if you have it installed). The page also displays which of your friends has it installed
Picture21.png

Dashboard

Provides access to all installed gadgets/apps in default/profile view format
Picture22.png

Application Canvas view

Application page for canvas view. You can also see the installed applications of your friends (the information inside will be displayed as for a simple viewer, and not the owner)
Picture23.png

User Profile

Added lists of friends and applications to profile
Picture26.png

May 25 2009

Setting Up the Project with Maven

Yesterday we got our own space on the XWiki sandbox. My space will be here: https://svn.xwiki.org/svnroot/xwiki/sandbox/gsoc/opensocial

We'll be using Maven as a project management tool, so I started with the Maven in 5 Minutes guide to see how it works. I have used Maven before only for building projects (like XWiki Core / Enterprise with the mvn install command) but nothing else.

Create the Project

So, I've created a Maven Project using the archetype:create goal (archetype is the Maven plugin and create the Maven goal - a plugin is a collection of goals)

mvn archetype:create -DgroupId=org.xwiki.platform -DartifactId=xwiki-opensocial

My project now has this simple, nice and perfect structure (soon to be messed up :) ) :

xwiki-opensocial
| --pom.xml
`-- src
    | --main
    |   `-- java
    |      ` --org
    |          `-- xwiki
    |              ` --opensocial
    |                  `-- App.java
    ` --test
         `-- java
            ` --org
                `-- xwiki
                    ` --opensocial
                        `-- AppTest.java

The src/main/java directory contains the project source code, the src/test/java directory contains the test source, and the pom.xml is the project's Project Object Model, or POM.

The POM is also nice and simple:

<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>
  <groupId>org.xwiki.platform</groupId>
  <artifactId>xwiki-opensocial</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>xwiki-opensocial</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>


Build the Project

mvn package

And I already build my project for the first time :) !! It also run 1 test :) and build the 1.0-SNAPSHOT jar file.

...
[INFO] Building jar: /Users/anamariastoica/Documents/workspace/xwiki-opensocial/target/xwiki-opensocial-1.0-SNAPSHOT.jar
[INFO] ----------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ----------------------------------------------------------------
[INFO] Total time: 7 seconds
[INFO] Finished at: Mon May 25 14:41:51 EEST 2009
[INFO] Final Memory: 8M/17M
[INFO]

package is a phase, not a goal. A phase is a step in the build lifecycle, which is an ordered sequence of phases.

Now let's test the JAR:

10-5-5-101:xwiki-opensocial anamariastoica$ java -cp target/xwiki-opensocial-1.0-SNAPSHOT.jar org.xwiki.opensocial.App
Hello World!


Import the Project in Eclipse

Next step was to import the project in Eclipse, and test the SVN by committing the project.

Committed revision 20406.

And here it is : https://svn.xwiki.org/svnroot/xwiki/sandbox/gsoc/opensocial/xwiki-opensocial/


More about Maven Phases

As this is new for me and seems important, I will take a few more notes about it.

A build lifecycle is made up of phases.

There are three built-in build lifecycles: default (handles project deployment), clean (handles project cleaning) and site (handles creation of project's site documentation), each of them having a different list of build phases.

For example, the default lifecycle has the following build phases:

  • validate - validate the project is correct and all necessary information is available
  • compile - compile the source code of the project
  • test - test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed
  • package - take the compiled code and package it in its distributable format, such as a JAR.
  • integration-test - process and deploy the package if necessary into an environment where integration tests can be run
  • verify - run any checks to verify the package is valid and meets quality criteria
  • install - install the package into the local repository, for use as a dependency in other projects locally
  • deploy - done in an integration or release environment, copies the final package to the remote repository for sharing with other developers and projects.
Calling a build phase, will not only execute it, but also all build phases above. For example if you call install, the build phases which are actually called are: validate, compile, test, package, integration-test, verify and install. To call all of them you must run mvn deploy.

This is a command I've actually used before to build the XWiki Core:

mvn clean install

This command will traverse into all of the subprojects and run clean, then install (including all of the prior steps).

Tags:
Created by Anamaria Stoica on 2009/04/22 21:26
Last modified by Anamaria Stoica on 2009/08/24 02:22

Workstream


This wiki is licensed under a Creative Commons 2.0 license
XWiki Enterprise 2.3-SNAPSHOT.27423 - Documentation