{"id":37720,"date":"2014-08-14T05:55:18","date_gmt":"2014-08-14T12:55:18","guid":{"rendered":"http:\/\/localhost\/exoblog\/?p=7379"},"modified":"2014-08-14T05:55:18","modified_gmt":"2014-08-14T12:55:18","slug":"extend-exo-cloud-drive-new-cloud-services-connector-api-customization-configuration-part-3-3","status":"publish","type":"post","link":"https:\/\/www.exoplatform.com\/blog\/extend-exo-cloud-drive-new-cloud-services-connector-api-customization-configuration-part-3-3\/","title":{"rendered":"Extend eXo Cloud Drive to new cloud services with the Connector API: Customization and configuration (Part 3 of 3)"},"content":{"rendered":"<p><a href=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/08\/CloudDrive-post3.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-medium wp-image-7393\" src=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/08\/CloudDrive-post3.jpg\" alt=\"CloudDrive-post3\" width=\"650\" height=\"200\" srcset=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/08\/CloudDrive-post3.jpg 650w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/08\/CloudDrive-post3-300x92.jpg 300w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/08\/CloudDrive-post3-500x154.jpg 500w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/08\/CloudDrive-post3-360x111.jpg 360w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/08\/CloudDrive-post3-200x62.jpg 200w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/08\/CloudDrive-post3-100x31.jpg 100w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/08\/CloudDrive-post3-70x22.jpg 70w\" sizes=\"(max-width: 650px) 100vw, 650px\" \/><\/a><\/p>\n<p><i>In case you missed them, you can quickly jump to the previous parts of the series:<\/i><\/p>\n<ul>\n<li><i><a href=\"https:\/\/www.exoplatform.com\/blog\/extend-exo-cloud-drive-new-cloud-services-connector-api-architecture-part-1-3\/\">The Architecture (Part 1 of 3)<\/a><\/i><\/li>\n<li><i><a href=\"https:\/\/www.exoplatform.com\/blog\/extend-exo-cloud-drive-new-cloud-services-connector-api-java-api-part-2-3\/\">The Java API (Part 2 of 3)<\/a><\/i><\/li>\n<\/ul>\n<p>In this post we will finish the introduction to Cloud Drive add-on\u2019s Connector API. As you already <a href=\"https:\/\/www.exoplatform.com\/blog\/extend-exo-cloud-drive-new-cloud-services-connector-api-architecture-part-1-3\/\">read in the first post<\/a>, the Cloud Drive is an add-on that connects cloud files into eXo. It is extensible, thanks to the Connector API, and we have already reviewed its <a href=\"https:\/\/www.exoplatform.com\/blog\/extend-exo-cloud-drive-new-cloud-services-connector-api-architecture-part-1-3\/\">architecture<\/a> and its <a href=\"https:\/\/www.exoplatform.com\/blog\/extend-exo-cloud-drive-new-cloud-services-connector-api-java-api-part-2-3\/\">Java API<\/a>.<\/p>\n<p>In this post you will learn how the client side can be customized via connector\u2019s CSS and Javascript API. We will end by seeing how configuration and packaging work.<br \/>\n<!--more--><\/p>\n<h2>Styles customization<\/h2>\n<p>The eXo Platform and Cloud Drive offer UI customization via CSS. Drives, files (by their mimetype), and menu icons already have dedicated class names. To add your styles you will need to follow the <a href=\"https:\/\/github.com\/exo-addons\/cloud-drive-extension\/blob\/master\/documentation\/CONNECTOR_API.md#conventions\" target=\"_blank\" rel=\"noopener\">conventions<\/a> and place a properly named file, with required class names, in the right place. Then, when your connector initializes the cloud provider via <a href=\"https:\/\/github.com\/exo-addons\/cloud-drive-extension\/blob\/master\/documentation\/CONNECTOR_API.md#ui-extensions\" target=\"_blank\" rel=\"noopener\">UI context<\/a>, this file will be loaded by the Cloud Drive client script. An example of how such a CSS file can look is in the <a href=\"https:\/\/github.com\/exo-addons\/cloud-drive-extension\/tree\/master\/connectors\/template\" target=\"_blank\" rel=\"noopener\">template project<\/a> in <a href=\"https:\/\/github.com\/exo-addons\/cloud-drive-extension\/\" target=\"_blank\" rel=\"noopener\">this file<\/a>.<\/p>\n<h2>Javascript client<\/h2>\n<p>Cloud Drive uses client side Javascript for better integration with existing user interface of eXo Platform. File icons and ECMS context menus are customized directly in the browser to reuse the existing applications infrastructure. The client is also responsible for initiation of new drives\u2019 connection and synchronization.<\/p>\n<p>Cloud Drive client it is an <a href=\"https:\/\/en.wikipedia.org\/wiki\/Asynchronous_module_definition\" target=\"_blank\" rel=\"noopener\">AMD<\/a> <a href=\"https:\/\/github.com\/exo-addons\/cloud-drive-extension\/blob\/master\/documentation\/CONNECTOR_API.md#javascript-api\" target=\"_blank\" rel=\"noopener\">module<\/a> registered in the Platform portal and loaded to ECMS Documents pages when the user opens a cloud drive folder. If the connector needs a custom Javascript, it should be registered as a module with the name <span class=\"navCode\">cloudDrive\/PROVIDER_ID<\/span>. Then it behaves similarly to CSS loading: if the module is available for a drive provider, it will be loaded by the client and used to serve the drive.<\/p>\n<p>One of important purposes of a connector Javascript is managing automatic synchronization. By default, the Cloud Drive client will do a periodic sync when a user opens the drive folder. But making periodic requests to the server isn\u2019t the best approach, especially when nothing changes remotely. If your cloud service can inform you of changes in real time (e.g. by a \u201clong-polling\u201d request), there is a way to leverage this via Connector API.<\/p>\n<p>Cloud Drive\u2019s Javascript is based on asynchronous processing; it uses jQuery Deferred internally to implement this technique. If the connector script has a method <span class=\"navCode\">onChange()<\/span> it will be used to obtain a Promise instance that will be used to <a href=\"https:\/\/github.com\/exo-addons\/cloud-drive-extension\/blob\/master\/documentation\/CONNECTOR_API.md#drive-state-monitoring\" target=\"_blank\" rel=\"noopener\">initiate the synchronization<\/a> during the work. In this case, the logic of your connector will manage when a next sync request will be invoked, thereby reducing network traffic and making the experience better for your users.<\/p>\n<p>If the client needs to deal with data specific only to your connector, Connector API offers several possibilities:<\/p>\n<ul>\n<li>each connected <a href=\"https:\/\/github.com\/exo-addons\/cloud-drive-extension\/blob\/master\/documentation\/CONNECTOR_API.md#cloud-drive\" target=\"_blank\" rel=\"noopener\">drive<\/a> may have a <i>state<\/i>\u2014an object of any type that also will be returned to a client as a part of the drive response (<a href=\"https:\/\/github.com\/exo-addons\/cloud-drive-extension\/blob\/master\/services\/core\/src\/main\/java\/org\/exoplatform\/clouddrive\/rest\/DriveService.java\" target=\"_blank\" rel=\"noopener\">\/clouddrive\/drive<\/a> web-service)<\/li>\n<li>you can implement your own RESTful service (somewhere at <span class=\"navCode\">\/clouddrive\/drive\/PROVIDER_ID<\/span>) and request it from custom client module.<\/li>\n<\/ul>\n<p>To customize or initialize the UI elements, the connector client can use jQuery.ready() handlers registered from its module. Below is a simplified example of a client module (it implements <span class=\"navCode\">onChange()<\/span> and read custom data from connector\u2019s REST-service):<\/p>\n<pre class=\"lang:default decode:true \">\/**\n * My Cloud support for eXo Cloud Drive.\n *\/\n(function($, cloudDrive, utils) {\n    \/**\n     * My Cloud connector class.\n     *\/\n    function MyCloud() {\n        \/\/ Provider Id for My Cloud\n        var PROVIDER_ID = \"mycloud\";\n        var prefixUrl = utils.pageBaseUrl(location);\n\n       \/**\n         * It is a method that Cloud Drive core client will look for when loading the connector module.   \n         * We request cloud service, when it will respond OK it will mean My Cloud drive has remote changes.\n         * Return jQuery Promise object that will be resolved when some change will appear, or rejected on error.\n         *\/\n        this.onChange = function(drive) {\n            var process = $.Deferred();\n            if (drive) {\n                if (drive.state) {\n                    var changes = cloudDrive.ajaxGet(drive.state.url);\n                    changes.done(function(info, status) {\n                        process.resolve(); \/\/ this will cause drive synchronization\n                    });\n                    changes.fail(function(response, status, err) {\n                        process.reject(\"Changes request failed on \" + drive.path + \". \" + err + \" (\" + status + \") \");\n                    }); \n                } else {\n                    process.reject(\"Cannot check for changes. No state object for Cloud Drive on \" + drive.path);\n                }\n            } else {\n                process.reject(\"Null drive in onChange()\");\n            }\n            return process.promise();\n        };\n        \n       \/**\n        * Request custom web-service (file comments) asynchronously and proceed data via jQuery Promise.\n        *\/\n       this.fileComments = function(workspace, path) {\n            return cloudDrive.ajaxGet(prefixUrl + \"\/portal\/rest\/clouddrive\/drive\/mycloud\", \n              {\"workspace\" : workspace, \"path\" : path});\n        };\n    };\n\n    var client = new MyCloud(); \/\/ client will be used below in DOM-ready handler \n\n    \/\/ On DOM-ready handler to initialize custom UI (or any other specific work on a client)\n    \/\/ We do initialization only if run in top window, not in iframe (gadgets doesn\u2019t need it)  \n    if (window == top) {\n        $(function() {\n            \/\/ Add an action to some button \"Show File Comments\"\n            $(\"#file_comments_button\").click(function() {\n                var drive = cloudDrive.getContextDrive();\n                var file = cloudDrive.getContextFile();\n                if (drive &amp;&amp; file) {\n                    var comments = client.readComments(drive.workspace, file.path);\n                    comments.done(function(commentsArray, status) {\n                        \/\/ Append comments to a some invisible div on the page and then show it\n                        var container = $(\"#file_comments_div\");\n                        $.each(commentsArray, function(i, c) {\n                            $(\"&lt;div class='myCloudFileComment'&gt;\" + c + \"&lt;\/div&gt;\").appendTo(container);\n                        });\n                        container.show();\n                    });\n                    comments.fail(function(response, status, err){ \n                        utils.log(\"Comments request failed. \" + err + \" (\" + status + \") \" + JSON.stringify(response));\n                    });\n                }\n            });\n        });\n    }\n    return client; \/\/ return client from the module\n})($, cloudDrive, cloudDriveUtils);<\/pre>\n<h2>Configuration<\/h2>\n<p>When code needs to be executed, you will need a configuration for your connector. Follow this <a href=\"https:\/\/github.com\/exo-addons\/cloud-drive-extension\/blob\/master\/connectors\/README.md\" target=\"_blank\" rel=\"noopener\">guide<\/a> to learn how to configure existing connectors, and use it to practice for new connectors. Instructions for creating a configuration of components and connector extension can be found <a href=\"https:\/\/github.com\/exo-addons\/cloud-drive-extension\/blob\/master\/documentation\/CONNECTOR_API.md#configuration\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>In general, each connector needs the following configurations:<\/p>\n<ul>\n<li>the connector\u2019s extension in <span class=\"navCode\">PortalContainerConfig<\/span>. The connector should depend on the Cloud Drive extension and has priority higher than 1000.<\/li>\n<li>The connector plugin of <span class=\"navCode\">CloudDriveService<\/span>. This defines all required parameters of the connector (ID, name, etc.)<\/li>\n<li>proper <span class=\"navCode\">display-name<\/span> in the WAR of the connector<\/li>\n<li>optionally it may need configuration of dedicated JCR namespaces and node types<\/li>\n<li>optionally it may need UI extensions configuration (e.g. when offering a dedicated connect-menu)<\/li>\n<li>optionally it may need CSS and Javascript configuration in the portal\u2019s <span class=\"navCode\">gatein-resources.xml<\/span><\/li>\n<li>finally, if component configuration relies on variables, you need to define variables in <span class=\"navCode\">configuration.properties<\/span> or via JVM settings of the server.<\/li>\n<\/ul>\n<h2>Packaging and Deployment<\/h2>\n<p>At some point, you will need to deploy your connector to a Platform server. There are several ways, but we recommend using a proper one: use eXo <a href=\"https:\/\/www.exoplatform.com\/blog\/add-ons-manager-1-0-0-rc2\/\">Add-ons manager<\/a>, a modern and friendly tool with a rich user experience. The Extension manager script, an older tool that already exists in eXo 4.0, can also do the job. In both cases you will need to package your connector as an add-on and make it available to the deployer.<\/p>\n<p>Our <a href=\"https:\/\/github.com\/exo-addons\/cloud-drive-extension\/tree\/master\/connectors\/template\" target=\"_blank\" rel=\"noopener\">template project<\/a> already contains a <i>packaging<\/i> artifact. It is able to package all connector files in an archive compatible with the add-ons managers. If your connector uses third-party libraries, add them in the Maven dependencies and the assembly of the packaging. Build the project and use the resulting zip-archive, from the packaging, as an add-on for the installation.<\/p>\n<p>An important notice about uninstallation: if you create some specific data that might damage the Platform in case of your add-on removal, consider using a correct uninstallation process. Note that dedicated UI actions, if they follow Cloud Drive UI <a href=\"https:\/\/github.com\/exo-addons\/cloud-drive-extension\/blob\/master\/documentation\/CONNECTOR_API.md#ui-extensions\" target=\"_blank\" rel=\"noopener\">requirements<\/a>, will be automatically removed by the core add-on.<\/p>\n<p>Done!<\/p>\n<p>So, there you are. Now it\u2019s time for you to create a new Cloud Drive connector and deploy it to the eXo Platform. Connector API opens a way for any developer to do this without changing the Cloud Drive code or configuration. I hope to see new connectors soon in the eXo Community.<\/p>\n<p>Have a good time coding!<\/p>\n<p><b><a href=\"https:\/\/community.exoplatform.com\/portal\/dw\/\" target=\"_blank\" rel=\"noopener\">Join the eXo tribe<\/a> by registering for the community and get updates, tutorials, support, and access to the Platform and add-on downloads!<\/b><\/p>\n<p><!--begin adv-events--><\/p>\n<div class=\"adv-events\" style=\"background: #476fad; padding: 30px 20px; color: white; border-radius: 3px;\">\n<div class=\"media\">\n<div class=\"pull-right\"><a href=\"#\"><br \/>\n<img decoding=\"async\" loading=\"lazy\" class=\"size-full wp-image-6587 alignright\" src=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/02\/how-to-make-the-most-of-eXo-platform41.png\" alt=\"make-the-most-out-of-eXo-platform4\" width=\"161\" height=\"85\"><br \/>\n<\/a><\/div>\n<div class=\"media-body\">\n<h4 class=\"media-heading\">Make the most out of eXo Platform 4<\/h4>\n<p>Register to the next webinar and get a complete overview of what you can do with eXo Platform 4. <strong><a href=\"https:\/\/www.exoplatform.com\/contact-us\/\">Reserve your seat now!<\/a><\/strong><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!--end adv-events--><\/p>\n","protected":false},"excerpt":{"rendered":"In case you missed them, you can quickly jump to the previous parts of the series: The Architecture (Part 1 of 3) The Java API (Part 2 of 3) In this post we will finish the introduction to Cloud Drive add-on\u2019s Connector API. As you already read in the first post, the Cloud Drive is [&hellip;]","protected":false},"author":7,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[699],"tags":[],"lang":"en","translations":{"en":37720},"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/posts\/37720"}],"collection":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/comments?post=37720"}],"version-history":[{"count":0,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/posts\/37720\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/media?parent=37720"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/categories?post=37720"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/tags?post=37720"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}