Create a Vimeo Proxy Asset in WebCenter Sites

image
In a previous article, Sridhar discussed Proxy Assets and how they work in WebCenter Sites. For example, say your site has lots of video content from Vimeo. In the past, maybe you created a string attribute to hold the Vimeo id, and maybe you even went so far as to create an attribute editor or Contributor UI customization to embed the video preview directly in the WebCenter UI. But you still had to search for videos in a separate browser window. And then you had to copy and paste the video id into WebCenter. With a Vimeo Proxy Asset type, you can search Vimeo for videos directly from the global search in the Contributor UI, and any results you find are stored as assets in WebCenter, no copying and pasting of ids or separate browser windows required.  Oracle's WCS Developer guide discusses Proxy Assets quite a bit, but its only example is a "dummy" repository. So how about a real example with Vimeo videos? 
 
Here's an outline (with links to each section) of how to create a Vimeo proxy asset. Bear with me... This post is a bit long since I've included all the code right on this page. 

 

First, create the Vimeo proxy asset type in the Admin UI (Admin UI > Admin tab > Proxy Asset Maker > Add New). Then, enable the Vimeo asset type for your site and create a Search type start menu.
 
 
Here we will write two elements:
 
This element will do the actual query using Vimeo APIs. It will put the results in a JSON object for the next element, SearchJson, and it will also add the results to WebCenter Sites as Proxy Assets. Before running this element, you will need to get an authorization token from vimeo.

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"

%><%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"

%><%@ taglib prefix="proxy" uri="futuretense_cs/proxy.tld"

%><%@ page import="COM.FutureTense.Interfaces.Utilities"

%><%@ page import="javax.xml.bind.DatatypeConverter"

%><%@ page import="java.util.*"

%><%@ page import="com.openmarket.xcelerate.util.ConverterUtils"

%><%@page import="com.fatwire.cs.ui.framework.UIException"

%><%@page import="COM.FutureTense.Interfaces.ICS"

%><%@ page import="org.json.JSONObject" %>

<%@ page import="org.apache.oltu.oauth2.common.exception.OAuthSystemException" %>

<%@ page import="org.apache.oltu.oauth2.common.exception.OAuthProblemException" %>

<%@ page import="org.json.JSONArray" %>

<%@ page import="org.json.JSONException" %>

<%@ page import="org.apache.oltu.oauth2.client.request.OAuthClientRequest" %>

<%@ page import="org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest" %>

<%@ page import="org.apache.oltu.oauth2.client.OAuthClient" %>

<%@ page import="org.apache.oltu.oauth2.client.URLConnectionClient" %>

<%@ page import="org.apache.oltu.oauth2.common.OAuth" %>

<%@ page import="org.apache.oltu.oauth2.client.response.OAuthResourceResponse" %>

<%@ page import="java.net.URLEncoder" %>

<cs:ftcs><%!

 

    public static final String BASE_VIMEO_URL = "https://api.vimeo.com";

    // TODO: Register on vimeo.com and replace with your key here

    private static final String AUTH_TOKEN = "YOUR_AUTH_TOKEN"

    

    /**

     * Calls method initApacheOauthStyle(ICS ics, String q) to query Vimeo and get the JSON response.

     * Then calls getVideoInfo(JSONObject json) to parse the response and get the data we want.

     * 

     * ics - The ICS Object

     * q - the search query

     **/    

    public List<Map> doVimeoSearch(ICS ics, String query, int page, int count, String orderBy) {

        JSONObject resp = null;

        try {

            resp = initApacheOauthStyle(ics, query);

        } catch (OAuthSystemException e) {

            e.printStackTrace();

        } catch (OAuthProblemException e) {

            e.printStackTrace();

        }

        List<Map> videos = new ArrayList<Map>();

        if(resp != null) {

            //getResultCount(ics, resp);

            if(resp != null) {

                Integer total = getIntegerVal(resp, "total");

                ics.SetVar("totalVimeoResults", total);

            }

            try {

                JSONArray data = resp.getJSONArray("data");

                if(data != null) {

                    int max = data.length() > 25 ? 25 : data.length();

                    for(int i=0 ; i < max; i++) {

                        Map<String,String> video = getVideoInfo(data.getJSONObject(i));

                        videos.add(video);

                    }

                }

            } catch (JSONException e) {

                e.printStackTrace();

            }

        }

        return videos;

    }

 

    /**

     * Uses the Vimeo API to run the search query. Returns the raw JSON response from Vimeo

     * 

     * ics - The ICS Object

     * q - the search query

     **/

    private JSONObject initApacheOauthStyle(ICS ics, String q) throws OAuthSystemException, OAuthProblemException {

        String encodedQ = q != null ? URLEncoder.encode(q) : "";

        String requestUrl = BASE_VIMEO_URL + "/videos?" + "query=" + encodedQ;

        OAuthClientRequest request = new OAuthBearerClientRequest(requestUrl)

                .setAccessToken(AUTH_TOKEN)

                .buildQueryMessage();

 

        //create OAuth client that uses custom http client under the hood

        OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());

 

        request.setHeader(OAuth.HeaderType.CONTENT_TYPE, "application/x-www-form-urlencoded; charset=UTF-8");

        request.setHeader("Accept", "application/vnd.vimeo.*+json;version=3.2");

        OAuthResourceResponse resourceResponse = oAuthClient.resource(request, OAuth.HttpMethod.GET, OAuthResourceResponse.class);

 

        JSONObject resp = null;

        try {

            resp = new JSONObject(resourceResponse.getBody());

        } catch (JSONException e) {

            e.printStackTrace();

        }

        return resp;

    }

 

    /**

     * Get # of results from JSON response, put in ICS var for later

     **/

    private void getResultCount(ICS ics, JSONObject resp) {

        if(resp != null) {

            Integer total = getIntegerVal(resp, "total");

            ics.SetVar("totalVimeoResults", total);

            Integer page = getIntegerVal(resp, "page");

            Integer perPage = getIntegerVal(resp, "per_page");

        }

        else {

            // response is NULL

        }

    }

 

    /**

     * Get Integer value from JSON object

     * json - JSON object

     * key - key in JSON object

     **/

    private Integer getIntegerVal(JSONObject json, String key) {

        try {

            if(json.get(key) != null)

                return json.getInt(key);

            else

                return 0;

        } catch (JSONException e) {

            return 0;

        }

    }

 

    /**

     * Get String value from JSON object

     * json - JSON object

     * key - key in JSON object

     **/

    private String getStringVal(JSONObject json, String key) {

        try {

            return (String)json.get(key);

        } catch (JSONException e) {

            return null;

        }

    }

 

    /**

     * Get thumbnail url for a video

     *

     * data - JSON object for one video

     **/

    private String getThumb(JSONObject data) {

        try {

            JSONObject pictures = data.getJSONObject("pictures");

            if(pictures != null) {

                JSONArray sizes = pictures.getJSONArray("sizes");

                if(sizes != null && sizes.length() > 0) {

                    JSONObject size = sizes.getJSONObject(0);

                    if(sizes.length() >= 2)

                        size = sizes.getJSONObject(1);

                    return getStringVal(size, "link");

                }

            }

        } catch (JSONException e) {

            return null;

        }

        return null;

    }

 

    /**

     * Get video url for a video from its JSON data

     *

     * data - JSON object for one video

     **/

    private Map<String,String> getVideoInfo(JSONObject json) {

        try {

            Map<String,String> video = new HashMap<String,String>();

            String name = getStringVal(json, "name");

            String link = getStringVal(json, "link");

            JSONObject stats = json.getJSONObject("stats");

            Integer plays = null;

            if(stats != null && stats.has("plays"))

                plays = getIntegerVal(stats, "plays");

 

            video.put("uri", getStringVal(json, "uri"));

            video.put("name", name);

            video.put("link", link);

            video.put("plays", Integer.toString(plays));

            video.put("thumbnail", getThumb(json));

            video.put("updateddate", getStringVal(json, "modified_time"));

            return video;

        } catch (JSONException e) {

            return null;

        }

    }

 

%><%

    try {

        // Get params to use in Vimeo search

        String start = ics.GetVar("start");

        String count = ics.GetVar("count");

        int startIndex = 1, resultsPerPage = 25;

        if (Utilities.goodString(start)) {

            startIndex = Integer.valueOf(start) + 1; // youtube start index is 1-based, ours is 0-based

        }

        if (Utilities.goodString(count)) {

            resultsPerPage = Integer.valueOf(count) + 1; // youtube start index is 1-based, ours is 0-based

        }

 

        int pageNo = startIndex > 1 ? (startIndex / resultsPerPage) : 0;

 

        // Do Vimeo search

        List<Map> searchResults = doVimeoSearch(ics, ics.GetVar("searchText"), pageNo, resultsPerPage, null);

        %><proxy:createstore store="assets" /><%

 

        // Process Vimeo search results, add as proxy assets

        for(Map result : searchResults) {

            %><proxy:register externalid='<%=(String)result.get("uri")%>' type="Vimeo" name='<%=(String)result.get("name")%>' varname="internalid" /><%

            String updated = (String)result.get("updateddate");

            Calendar cal = DatatypeConverter.parseDateTime(updated);

            Date updatedDate = cal.getTime();

            %><proxy:addstoreitem store="assets" id='<%=ics.GetVar("internalid") %>' type="Vimeo">

                <proxy:argument name="thumbnailURL" value='<%=(String)result.get("thumbnail")%>' />

                <proxy:argument name="updateddate" value='<%=ConverterUtils.getLocalizedDate(ics, updatedDate) %>' />

                <proxy:argument name="viewed" value='<%=(String)result.get("plays")%>' />

            </proxy:addstoreitem><%

        }

        // set store name and totalRows in request

        request.setAttribute("store", "assets");

        request.setAttribute("totalRows", ics.GetVar("totalVimeoResults"));

 

 

    } catch(Exception e) {

        UIException uie = new UIException(e);

        request.setAttribute(UIException._UI_EXCEPTION_, uie);

        throw uie;

    }

%></cs:ftcs>

 
 
 
This is practically a one-line element that converts the results to JSON for the UI to use.

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"

%><%@ taglib prefix="proxy" uri="futuretense_cs/proxy.tld"

%><%@ page import="org.codehaus.jettison.json.JSONArray"

%><%@ page import="org.codehaus.jettison.json.JSONObject"

%><cs:ftcs><proxy:tojson store="${store}" total="${totalRows}" /></cs:ftcs>

 
 
[[{"type":"media","view_mode":"media_large","fid":"2345","attributes":{"alt":"","class":"media-image","height":"300","width":"480"}}]]
Here will create two elements to configure the list and thumbnail view search results. These look like the ListViewConfig and ThumbnailViewConfig you would create for any other asset type in OWCS.
 
 

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"

%><%@ taglib prefix="xlat" uri="futuretense_cs/xlat.tld"

%><cs:ftcs>

     <listviewconfig>

        <numberofitems>1000</numberofitems>

        <numberofitemsperpage>25</numberofitemsperpage>

        <pagestepsize>"10", "25"</pagestepsize>

        <fields>

            <field id="name">

                <fieldname>name</fieldname>

                <displayname><xlat:stream key="dvin/AT/Common/Name"/></displayname>

                <width>350px</width>

                <formatter>fw.ui.GridFormatter.nameFormatter</formatter>

                <displayintooltip>true</displayintooltip>

            </field>

            <field id="updateddate">

                <fieldname>updateddate</fieldname>

                <displayname><xlat:stream key="dvin/Common/Modified"/></displayname>

                <width>160px</width>

                <formatter></formatter>

                <displayintooltip>true</displayintooltip>

            </field>

            <field id="viewed">

                <fieldname>viewed</fieldname>

                <displayname><xlat:stream key="UI/UC1/Layout/ViewCount" escape="true"/></displayname>

                <width>auto</width>

                <formatter></formatter>

                <displayintooltip>true</displayintooltip>

            </field>

        </fields>

    </listviewconfig>

</cs:ftcs>

 
 

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld" %>

<%@ taglib prefix="xlat" uri="futuretense_cs/xlat.tld" %>

<cs:ftcs>

    <thumbnailviewconfig>

        <formatter>fw.ui.GridFormatter.simpleThumbnailFormatter</formatter>

        <numberofitemsperpage>25</numberofitemsperpage>

        <pagestepsize>"10", "25"</pagestepsize>

    </thumbnailviewconfig>

</cs:ftcs>

 
 
Here we will create the element that will embed the Vimeo video into the Contributor UI inspect view of the proxy asset.
 
Most of this is the same as the YouTube proxy asset code, except a few lines in the middle where we display the Vimeo iframe. 

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"

%><%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"

%><%@ taglib prefix="asset" uri="futuretense_cs/asset.tld"

%><%@ taglib prefix="assettype" uri="futuretense_cs/assettype.tld"

%><%@ taglib prefix="dateformat" uri="futuretense_cs/dateformat.tld"

%><%@ taglib prefix="string" uri="futuretense_cs/string.tld"

%><%@ taglib prefix="locale" uri="futuretense_cs/locale1.tld"

%><%@ taglib prefix="xlat" uri="futuretense_cs/xlat.tld"

%><%@ page import="COM.FutureTense.Interfaces.*" %><cs:ftcs>

<ics:callelement element="OpenMarket/Xcelerate/UIFramework/StandardVariables" />

<html>

<head>

    <ics:callelement element="OpenMarket/Xcelerate/UIFramework/StandardHeader" />

    <ics:callelement element="OpenMarket/Xcelerate/UIFramework/LoadDojo" />

    <ics:callelement element="OpenMarket/Xcelerate/UIFramework/Util/SetStylesheet" />

</head>

    <body>

        <ics:if condition='<%=Utilities.goodString(ics.GetSSVar("locale")) %>'>

        <ics:then>

            <locale:create varname="LocaleName" localename='<%=ics.GetSSVar("locale") %>'/>

            <dateformat:create name="_FormatDate_" datestyle="full" timestyle="full" locale="LocaleName" timezoneid='<%=ics.GetSSVar("time.zone") %>'/>

        </ics:then>

        <ics:else>

            <dateformat:create name="_FormatDate_" datestyle="full" timestyle="full" timezoneid='<%=ics.GetSSVar("time.zone") %>'/>

        </ics:else>

        </ics:if>

        

        <ics:setvar name="assetname" value="theCurrentAsset" />

        <asset:load type='<%=ics.GetVar("type") %>' objectid='<%=ics.GetVar("id") %>' name="theCurrentAsset"/>

        <asset:scatter name="theCurrentAsset" prefix="ContentDetails" />

        <asset:getassettype name="theCurrentAsset" outname="at"/>

        <assettype:get name="at" field="description" output="at:description"/>

 

        <table class="width-outer-70" style="padding-top: 35px;">

        <tr>

            <td><span class="title-text"><string:stream variable="at:description" />: </span><span class="title-value-text"><string:stream variable="ContentDetails:name"/></span></td>

        </tr>

        <ics:callelement element="OpenMarket/Xcelerate/UIFramework/Util/TitleBar">

            <ics:argument name="SpaceBelow" value="No"/>

        </ics:callelement>

        <tr>

            <td>

            <table border="0" cellpadding="0" cellspacing="0">

                <tr>

                    <td class="form-label-text"><xlat:stream key="dvin/Common/Name"/>:</td>

                    <td><img height="1" width="5" src="<ics:getvar name="cs_imagedir" />/graphics/common/screen/dotclear.gif" /></td>

                    <td class="form-inset"><string:stream variable="ContentDetails:name"/></td>

                </tr>

                <ics:callelement element="OpenMarket/Xcelerate/UIFramework/Util/RowSpacer"/>

                                <tr>

                    <td class="form-label-text"><xlat:stream key="UI/UC1/Layout/Tags"/>:</td>

                    <td><img height="1" width="5" src="<ics:getvar name="cs_imagedir" />/graphics/common/screen/dotclear.gif" /></td>

                    <td class="form-inset">

                                            <ics:callelement element="OpenMarket/Gator/AttributeTypes/TagBox">

                                                <ics:argument name="inputName" value='fwtags'/>

                                                <ics:argument name="tagValue" value='<%=ics.GetVar("fwtags")%>'/>

                                                <ics:argument name="inputSize" value='32'/>

                                                <ics:argument name="readOnly" value='true'/>

                                                <ics:argument name="showCloseButton" value='false'/>

                                                <ics:argument name="inputMaxlength" value='<%=ics.GetVar("sizeofnamefield")%>'/>

                                                <ics:argument name="applyDefaultFormStyle" value='<%=ics.GetVar("defaultFormStyle")%>' />

                                            </ics:callelement>

                                        </td>

                </tr>

                                <ics:callelement element="OpenMarket/Xcelerate/UIFramework/Util/RowSpacer"/>

                <tr>

                    <td class="form-label-text">Video:</td>

                    <td></td>

                    <td class="form-inset">

                        <asset:list list="asset" excludevoided="true" type="Vimeo" field1='id' value1='<%=ics.GetVar("id") %>'/>

                        <ics:listget listname="asset" fieldname="externalid" output="videoId" />

                        <%

                            if(Utilities.goodString(ics.GetVar("videoId"))) {

                                ics.SetVar("videoId", ics.GetVar("videoId").replaceAll("videos", "video"));

                            }

                        %>

                        <iframe id="ytplayer" type="text/html" width="640" height="360"

                                src="//player.vimeo.com<ics:getvar name="videoId"/>" frameborder="0"></iframe>

                    </td>

                </tr>

                <ics:callelement element="OpenMarket/Xcelerate/UIFramework/Util/RowSpacer"/>

                <tr>

                    <td class="form-label-text"><xlat:stream key="dvin/AT/Common/ID"/>:</td>

                    <td></td>

                    <td class="form-inset"><string:stream variable="ContentDetails:id"/></td>

                </tr>

                <ics:callelement element="OpenMarket/Xcelerate/UIFramework/Util/RowSpacer"/>

                <tr>

                    <td class="form-label-text"><xlat:stream key="dvin/FlexibleAssets/FlexAssets/ExternalItemId"/>:</td>

                    <td></td>

                    <td class="form-inset"><string:stream variable="ContentDetails:externalid"/></td>

                </tr>

                <ics:callelement element="OpenMarket/Xcelerate/UIFramework/Util/RowSpacer"/>

                <tr>

                    <td class="form-label-text"><xlat:stream key="dvin/AT/Common/Created"/>:</td>

                    <td></td>

                    <td class="form-inset">

                        <dateformat:getdatetime name="_FormatDate_" value='<%=ics.GetVar("ContentDetails:createddate") %>' valuetype="jdbcdate" varname="ContentDetails:createddate"/>

                        <xlat:stream key="dvin/UI/ContentDetailscreateddatebycreatedby"/>

                    </td>

                </tr>

                <ics:callelement element="OpenMarket/Xcelerate/UIFramework/Util/RowSpacer"/>

                <tr>

                    <td class="form-label-text"><xlat:stream key="dvin/AT/Common/Modified"/>:</td>

                    <td></td>

                    <td class="form-inset">

                        <dateformat:getdatetime name="_FormatDate_" value='<%=ics.GetVar("ContentDetails:updateddate") %>' valuetype="jdbcdate" varname="ContentDetails:updateddate"/>

                    <xlat:stream key="dvin/UI/ContentDetailsupdateddatebyupdatedby"/></td>

                </tr>

            </table>

        </td>

    </tr>

    </table>

    </body>

</html>

</cs:ftcs>

 
 
Here we will create the Summary template that will be used to display the video on your website.

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"

%><%@ taglib prefix="asset" uri="futuretense_cs/asset.tld"

%><%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"

%><%@ taglib prefix="render" uri="futuretense_cs/render.tld"

%><%@ page import="COM.FutureTense.Interfaces.*,

                   COM.FutureTense.Util.ftMessage,

                   COM.FutureTense.Util.ftErrors"

%><cs:ftcs>

<%-- Record dependencies for the Template --%>

<ics:if condition='<%=ics.GetVar("tid")!=null%>'><ics:then><render:logdep cid='<%=ics.GetVar("tid")%>' c="Template"/></ics:then></ics:if>

 

<asset:list list="asset" excludevoided="true" type="Vimeo" field1='id' value1='<%=ics.GetVar("cid") %>'/>

<ics:listget listname="asset" fieldname="externalid" output="videoId" />

<%

    if(Utilities.goodString(ics.GetVar("videoId"))) {

        ics.SetVar("videoId", ics.GetVar("videoId").replaceAll("videos", "video"));

    }

%>

<iframe src="//player.vimeo.com<ics:getvar name="videoId"/>" width="800" height="400" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>

 

</cs:ftcs>

 
 
And that's about all you need to create your own proxy asset. Happy coding!
 
P.S.  Here's that amazing surfing video from the screenshot above.
 

Subscribe to Our Newsletter

Stay In Touch