AdoptOS

Assistance with Open Source adoption

ECM

Crafting document download links in a velocity asset publisher ADT

Liferay - Thu, 01/19/2017 - 18:19
This short post brings together the little pieces critical to crafting an ADT in velocity to provide direct download links to documents in your Documents and Media repository. You will find parts of this solution strewn across forums and blogs.    In essence, you'll have to do two things: 1. Add the following property to your portal-ext.properties if you have not done so yet. If you've been using the serviceLocator to pull in various Liferay service APIs in your ADTs, then you've likely done this already. velocity.engine.restricted.variables=   That just says no variables are restricted in your ADTs.   2. Craft the document's download URL. Your document download URL should looks like this: /documents/<groupId>/<folderId>/<document-title>/<document-uuid>?version=<version> For example: /documents/10181/11405/College+Sample+Doc.docx/7a5680cf-8de5-4d65-b179-72ee5c9f5966?version=1.0   Here's the velocity markup to do the above. There are freemarker versions of this all over the place.    #set($dlFileEntryLocalService = $serviceLocator.findService("com.liferay.portlet.documentlibrary.service.DLFileEntryLocalService")) <div> #if (!$entries.isEmpty()) #foreach ($curEntry in $entries)             #set($assetRenderer = $curEntry.getAssetRenderer())             #set($title = $htmlUtil.escape($assetRenderer.getTitle($locale)))             ### only show matching document types, skip over other types             #if($assetRenderer.getType() == "document")                 #set($fileEntryId = $assetRenderer.getClassPK())                 #set($fileEntry = $dlFileEntryLocalService.getFileEntry($fileEntryId))                 #set($version = $fileEntry.getLatestFileVersion(false))                 #set($viewURL = $themeDisplay.getPortalURL() + $themeDisplay.getPathContext() + "/documents/" + $fileEntry.getGroupId() + "/" + $fileEntry.getFolderId() + "/" + $httpUtil.encodeURL($htmlUtil.unescape($fileEntry.getTitle())) + "/" + $fileEntry.getUuid() + "?version=" + $version.getVersion())                 <a href="$viewURL" target="_new">$title</a>             #end              <br/>     #end #end     </div>   In the above code, you may have noticed the call: $fileEntry.getLatestFileVersion(false)   That boolearn parameter is named trusted, and basically, this is what the code looks like in the implementation (just in case you're curious).   public DLFileVersion getLatestFileVersion(boolean trusted) throws PortalException, SystemException {   if (trusted) {     return DLFileVersionLocalServiceUtil.getLatestFileVersion(getFileEntryId(),false);   }  else {     return DLFileVersionServiceUtil.getLatestFileVersion(getFileEntryId());   } }   I think that means that if trusted is true, then the working copy (Draft) is heeded as the latest version. Otherwise it is not. (Call me out on that if I'm off the mark.)   Hope this saves someone out there a little time. Javeed Chida 2017-01-19T23:19:47Z
Categories: CMS, ECM

My First Three Months With WeDeploy

Liferay - Mon, 01/16/2017 - 14:36

Hey! My name is Jonni and I'm a UI intern on the WeDeploy team. I joined back in November and wanted to share a couple things from my first three months at Liferay.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I have no coding background. Before my internship, I had never opened DevTools in my life and I thought that Java and JavaScript were the same thing.

Needless to say, I was a little intimidated of coming in as the new guy, but once I started using WeDeploy and working with the team, those fears drifted away like a bunch of balloons strapped to a house ('UP' anyone?).

I still remember the first time I deployed. I had just finished making my very first website, and Zeno said I should try deploying it by myself. I honestly didn't know where to start, so I went to the docs, read through some guides, and gave it a shot.

In 15 min, it was live!

It was one of the best feelings I've had during this internship. Knowing that I, the new guy who didn't know what an API was or how to run 'npm install', could deploy my own website faster than it takes me to run to Starbucks and get my triple ristretto hazelnut latte (with almond milk please).

 

 

By far my favorite thing about being on the WeDeploy team is being able to get behind a product that is so powerful and yet incredibly intuitive to use.

If I can deploy, then I'm sure you can! So what are you waiting for?!

Jonathan Lundy 2017-01-16T19:36:48Z
Categories: CMS, ECM

Tutorial of using Chart.js in Soy Portlet

Liferay - Thu, 01/12/2017 - 11:51
The purpose of this tutorial is to let you know how to involve a 3rd part js lib in metal soy portlet and how to use them in ES6 script.    In Liferay DXP we provide abundant OOTB js lib to help the development. Jquery, AlloyUI, metal, lexicon component and etc.   They are all good, however, in real world project development nothing can satisfy the requirement once for all. In this changing world, the requirement is unpredictable.  For this we can extend our ootb library by utilizing nodeJS to get 3rd part js lib works in Liferay.   In this journey, I will lead you to take a glimpse of the power of Liferay's integrability.   Knowledge:     Google Closure Soy template.     Liferay Soy Portlet.     ECMA script 2015(ES6)     Chart.js   In Tutorial of Creating Soy Portlet article, we have learned how to create a metal soy portlet by Liferay IDE.    Based on that, we are going to do a further development -- to create a Chart. (In my professional, many business requirement needs some sense of chart, this kind of requirement is very common.) To build a chart js lib from scratch is not realistic. By utilizing Chart.js or other product on the market would help us to reduce develop effort and save project cost.   So let's start working on a portlet that display a chart.   Step 1, Create a soy portlet.   Create a Soy portlet as it shows in Tutorial of Creating Soy Portlet article with this file structure:     Step 2, ChartJS dependencies   To use ChartJS, we need to add NodeJS dependencies in package.json. Optionally you could manually copy a Chart.js bundle to your project path.   "chart.js": "^2.4.0"   Step 3, include it to your runtime environment.   Because Chart.js is a 3rd part js lib, it doesn't exist in the system(suppose it's not been used before). We have to involve it in our runtime -- in the jar. So let's config our bnd.bnd to include the js to the right place. Add/Modify the following code to your bnd.bnd   Include-Resource: package.json,\ META-INF/resources/js/Chart.js = node_modules/chart.js/dist/Chart.js This means, I want a Chart.js in META-INF/resources/js of the jar, and the source is from node_modules/chart.js/dist/Chart.js And add web context path in bnd.bnd Web-ContextPath: /chartjs-soy     Step 4, Work with soy template   We are going to add a canvas for chart to use. So let's add the following code to ChartjsSoy.soy {namespace ChartjsSoy} /** * Display Chart canvas */ {template .render} <canvas id="chartjs-soy"> </canvas> {/template}     Step 5, import your Chart.js in your Component   I believe all audience of this blog know how to use ChartJS in a traditional way, in html and javascript like this: <script src="Chart.js"></script> <script> var myChart = new Chart({...}) </script> But this is not going to be our approach. We are going to take advantage ES6 to use Chart, to extend our knowledge :) So add the import in ChartjsSor.es.js in the head   import Chart from 'chartjs-soy/js/Chart';   You can see chartjs-soy is the web context path we define in bnd.bnd, and js/Chart is our web resource folder.     Step 6, create a chart with Chart.js   Add the following method to your Component /** * Create Chart * * @protected */ createChart_() { let chartcanvas = document.getElementById("chartjs-soy"); let data = { labels: ["January", "February", "March", "April", "May", "June", "July"], datasets: [ { label: "My First dataset", backgroundColor: [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)' ], borderColor: [ 'rgba(255,99,132,1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)' ], borderWidth: 1, data: [65, 59, 80, 81, 56, 55, 40], } ] }; let options = { scales: { xAxes: [{ stacked: true }], yAxes: [{ stacked: true }] } }; let myBarChart = new Chart(chartcanvas, { type: 'bar', data: data, options: options }); }   Step 7, constructor method to call   Let's add a constructor method in our component to call this createChart method   constructor(opt_config) { super(opt_config); this.createChart_(); }     Step 8, compile, deploy, test, debug and play around   If you have done it correctly, you would have a chart sheet like mine.     You can see how easy we can involve a 3rd part js lib in our project to improve our UX. Don't be limited with only 1 js lib, play around and test! The only limitation is your imagination.    Hope you enjoy it. Attachment is a compiled jar for you to deploy and test. For full workable source code please visit sample.liferayee.com   Special Thanks to our Principal UI Engineer Chema Balsas, with his help I can get this tutorial done. Thanks Chema for many precious recommendations and help. Neil Jin 2017-01-12T16:51:01Z
Categories: CMS, ECM

Tutorial of creating soy portlet

Liferay - Tue, 01/10/2017 - 10:23
In Liferay DXP it supports soy template with portlet. Through soy template we can take advantage of Google Closure to build rich web application.   In next sections I am going to lead you in to a journey of Soy portlet.   Tools we use:      Liferay IDE 3.1. -- Super awsome official tool to help us to create project and run gradle task.     Atom Editor. -- Professional UI development tool.(Or you can use whatever you are familiar tool)     Git Bash -- Reversion control and windows - Linus EOL/EOF convert.   Knowledge:     Familiar with Liferay OSGi portlet module development. If you are a stranger of this, please check this blog to learn how to create a mvc portlet.     Familiar with NodeJS development.     Familiar with Git     Step 1 Portlet Creation with soy frame work   Let's create a mvc portlet module. In my case I call my project sample-soy. The difference between soy portlet and mvc portlet class is soy portlet class extends SoyPortlet com.liferay.portal.portlet.bridge.soy.SoyPortlet which is a child class of MVCPortlet. Modify the super class to be SoyPortlet So you need to add the dependency to build.gradle correspondingly. compileOnly group: "com.liferay", name: "com.liferay.portal.portlet.bridge.soy", version: "3.0.0"   Make your Soy portlet component annotation like this:   @Component( immediate = true, property = { "com.liferay.portlet.add-default-resource=true", "com.liferay.portlet.application-type=full-page-application", "com.liferay.portlet.application-type=widget", "com.liferay.portlet.css-class-wrapper=table-wrapper", "com.liferay.portlet.display-category=category.sample", "com.liferay.portlet.header-portlet-css=/SoySample.css", "com.liferay.portlet.layout-cacheable=true", "com.liferay.portlet.preferences-owned-by-group=true", "com.liferay.portlet.private-request-attributes=false", "com.liferay.portlet.private-session-attributes=false", "com.liferay.portlet.render-weight=50", "com.liferay.portlet.scopeable=true", "com.liferay.portlet.use-default-template=true", "javax.portlet.display-name=Soy Sample Portlet", "javax.portlet.expiration-cache=0", "javax.portlet.init-param.copy-request-parameters=true", "javax.portlet.init-param.template-path=/", "javax.portlet.init-param.view-template=SoySample", "javax.portlet.name=soy_sample_portlet", "javax.portlet.resource-bundle=content.Language", "javax.portlet.security-role-ref=guest,power-user,user", "javax.portlet.supports.mime-type=text/html" }, service = Portlet.class ) According to this annotation, we will have SoySample.soy as our defaule view. We will have SoySample.scss for our css style   Step 2 node config file   In the build tool, we utilize NodeJS to build and compile UI elements soy, metal, other js, css, and etc. Create a package.json in project root folder with content: { "dependencies": { "metal-component": "^2.4.5", "metal-soy": "^2.4.5" }, "devDependencies": { "liferay-module-config-generator": "^1.1.10", "metal-cli": "^1.3.1" }, "name": "soy-sample", "version": "1.0.0" } It's a good practice that make the version be consistent with version in bnd.bnd     Step 3 OSGi config   Add the following code to the bnd.bnd so that bnd tool knows package.json need to be in the jar file, and the OSGi bundle need soy capability.   Include-Resource: package.json Require-Capability: soy;filter:="(type=metal)"   Step 4 Use Render method to define variables in soy template.   Add/Modify your render method in portlet class. @Override public void render( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { template.put("msg", "Good Job!"); super.render(renderRequest, renderResponse); }   We will have a parameter in our soy template called msg with the a string value "Good Job!"     Step 5 SoySample template   Create a file called SoySample.soy in this path src/main/resources/META-INF/resources/resources With the following code: {namespace SoySample} /** * Show portlet message in the view. * @param id * @param msg */ {template .render} <div id="{$id}"> <div class="form-group"> <div class="input-group"> <span class="input-group-addon" id="inputGroupAddon01">Message:</span> <input aria-describedby="inputGroupAddon01" class="form-control" value="{$msg}" type="text"> </div> </div> <div class="form-group"> <div class="input-group"> <input aria-describedby="inputGroupAddon02" class="form-control" placeholder="Recipient's username, ex. neil.jin ;)" type="text"> <span class="input-group-addon" id="inputGroupAddon02">@liferay.com</span> </div> </div> <div class="form-group"> <div class="input-group"> <span class="input-group-addon">$</span> <input aria-label="Amount" class="form-control" type="text"> <span class="input-group-addon">.00</span> </div> </div> <div class="form-group"> <button class="btn btn-default" type="button">Donate</button> </div> </div> {/template}   Closure require the template's declaration in java-doc like comment. So the comment about the {templlate .render} is required. All the param has to be used in the template. And {template .render} has to be the beginning or the line without and space characters.   Everytime you change the soy file, it's better to run build soy gradle task to generate soy.js   In my template I utilized Lexicon to build my UX.   In the same folder, create a file called SoySample.scss, just leave it blank.   Run buildSoy gradle command.   Step 6 test and check.   Now you can build your module and deploy the jar to your Liferay server and test. If everything is correct you are suppose to see this view from your portlet.   When you build, the task tries to download necessary node_modules, it might take a while(about 100m).  Sometimes it get stuck on npmInstall, you can stop the process and build again, it will work.   Step 7 javascript actions   I am going to add javascript to my soy template. Create a file called SoySample.es.js with the same folder of SoySample.soy with the following code:   import Component from 'metal-component/src/Component'; import core from 'metal/src/core'; import dom from 'metal-dom/src/dom'; import Soy from 'metal-soy/src/Soy'; import templates from './SoySample.soy'; class SoySample extends Component { } //Register component Soy.register(SoySample, templates); export default SoySample; Our js framework is done.   Step 8 add javascript method   We are going to create a donate method to send out a message to our js concole. Add the following method to the class SoySample   /** * donate to neil * * @param {MouseEvent} event */ donate(event) { console.log("donate successful"); }   Step 9, use method   We will make this method be executed when user click donate button, so add data-onclick="donate" attribute to donate button. It will look like this:   <button class="btn btn-default" data-onclick="donate" type="button">Donate</button>   After you have done everything, you can start build and deploy your project. When you click on donate button, your browser console should show  a message "donate successful"     Troubleshoot: Because of an issue of soy compiler, the compiler can't identify the end of line and end of file character. We have to manually convert CRLF to LF. On windows you may meet js error "TypeError: fn is not a function" in the browser.   To solve this we are going to utilize git. You can create a file in your project's git repo named  .gitattributes, with the following content: *.pom text eol=lf *.soy text eol=lf ivy.xml text eol=lf After you have added your work to the index and commit, the CRLF should be automatically converted to LF.   You can also take advantage of IDE 3.1 with AnyEdit eclipse plugin. (Thanks @Greg for the info)   You can also utilize Atom Editor with line-ending-selector   Hope you enjoy. The attachment is a compiled soy portlet jar, you can downlad and deploy to your portal for a test. Sample Soy Jar   For a workable project source code you can visit http://sample.liferayee.com/tree/master/sample-workspace/sample-liferay-workspace/modules/sample-soy to download Neil Jin 2017-01-10T15:23:11Z
Categories: CMS, ECM

繁体译文 OSGi Module依赖

Liferay - Sat, 01/07/2017 - 08:52

原文作者:David H Nebinger

原文地址:https://web.liferay.com/web/user.26526/blog/-/blogs/osgi-module-dependencies

如有問題,歡迎在原文下面討論,也歡迎在這裡留言。

 

假設在Liferay DXP平臺上開發module的時候,遇見了需要運行環境(runtime)的依賴的時候,該怎麼辦?

在這片簡短的文章中,我會介紹幾種方法...

假設你有一個module需要iText(和iText的依賴)作為依賴。這其實和module本身的功能關係不是很大,但是你現在有這個依賴,需要一種方法來使用它。

 

方法 1 - 放在全域(global)目錄下

 

這種方法最簡單也最粗暴。所有在全域類載入器(比如tomcat的lib和lib/ext)中的類可以被所有類訪問,包括Liferay OSGi容器。

但是全域的jar有全域的問題。不僅所需要的jar需要在全域目錄,所有jar的依賴也需要在全域目錄。並且全域類只有一個版本,其他的消費類無法使用不同的版本。

 

方法 2 - 讓OSGi處理

 

這個是第二簡單的方法,但是可能無法使用。如果你在module中聲明一個運行環境的依賴,並且OSGi中有一個bundle可以滿足依賴的話,module會使用使用這個依賴。

當你確認OSGi中依賴可以被使用的時候,這個方法就可以使用。因為這個方法是利用portal中已有的依賴,或者你之前已經部署到OSGi容器中的依賴(有些jar可能已經包含了OSGi bundle的資訊,可以直接部署到容器中)。

例如,假設我們要聲明iText依賴,雖然iText應該不會作為bundle已經部署到了OSGi中,所以如果依賴OSGi容器來使用iText很可能會出錯的。現在僅是用作舉例

使用build.gradle檔來聲明運行環境依賴。這段代碼是用來聲明iText運行環境依賴的

runtime group: 'com.iowagie', name: 'itext', version: '1.4.8'

如果iText(和其依賴)已經成功的部署到OSGi容器中,通過運行環境依賴聲明就可以在你自己的module中使用了。如果iText不可用,你的module就不會啟動,並且會報錯 -- 依賴無法滿足。

 

方法 3 - 製作成一個超級胖子Module

 

像那些巨型jar一樣,巨型module會擁有所有依賴的類直接暴露在module jar中。

使用Gradle和BND很好實現。

在build.gradle中,你應該像方法2中一樣聲明運行環境依賴。

並且通過在bnd.bnd中包含所需的資源使module成為一個巨型module:

Include-Resource: @itext-1.4.8.jar

在這裡引入依賴jar,一般在gradle下來依賴或者流覽maven庫的時候都可以看到具體版本。

要注意的是,也需要引入依賴所以依賴的jar。例如,iText2.08依賴於BouncyCasle mail和prov,所以這些依賴也需要添加:

Include-Resource: @itext-2.0.8.jar,@bcmail-138.jar,@bcprov-138.jar

也需要在build.gradle中添加這些依賴,以便gradle引入這些jar。

如果使用zip工具打開module jar包的話,會看見所有依賴的jar會被解壓,class檔會被直接放在module jar包中。

 

方法 4 - 在Module中引入整個jar

 

最後的方法是在module中引入jar,和巨型module不一樣,這個方法將整個jar包含到module jar中

和方法2,3相似的是,也需要在build.gradle中聲明運行環境依賴。

引用jar是在bnd.bnd中完成的。

首先需要定義Bundle-ClassPath屬性來引入module jar和其餘的依賴jar。在下面的例子中,我指定iText jar會包含在module jar中:

Bundle-ClassPath:\ .,\ lib/itext.jar

這裡我們不使用Include-Resource聲明,而是使用-includeresource來-將jar引入到bundle中:

-includeresource:\ lib/itext.jar=itext-1.4.8.jar

在這裡,我們將itext-1.4.8.jar包含到module中,保存為lib/itext.jar。itext-1.4.8是通過Gradle導入的運行環境依賴。

這種語法也支援萬用字元,可以有效利用build.gradle選擇版本的特性。這個例子是用來包含任何版本的commons-lang:

-includeresource:\ lib/itext.jar=itext-1.4.8.jar,\ lib/commons-lang.jar=commons-lang=[0-9]*.jar

如果使用壓縮軟體打開module的jar檔的話,可以看到jar檔會在lib資料夾下。

 

總結

 

實際項目中應該使用哪種方法?和Liferay開發一樣,因需而異。

全域方法適用於只需要一種版本的jar包並且需要用到大量的依賴的情況。例如,專案中有20個不同的module全部依賴於iText 1.4.8,這樣,全域方法就是最好的選擇。

第二種方法只用於依賴jar是OSGi bundle的情況。在這種情況下,你可以使用不同的版本,並且不用擔心去編輯bnd檔。

第三種和第四種方法是最常用的放法。在上面這些情境下,你的依賴是包含在module中的,OSGi類容器中的類是不會被不同版本的ja“污染”的。並且,module也是不依賴於當前容器環境的,因為module自己已經包含了所有的依賴,運行環境也不需要為module事前準備依賴。

我個人很喜歡使用第四種方法,以為巨型jar在解壓縮類的時候,可能會有路徑上的交錯(例如xml和設定檔)。第四種方法就不會有這樣的問題。

 

希望你喜歡

 

譯者補充:

在使用方法3,4的時候,OSGi容器會要求導入要引用jar的所有依賴,這樣的結果是,需要導入無盡的包,因為依賴還有依賴,依賴還有依賴,子子孫孫無窮匱也。

 

所以,需要通過bnd.bnd來聲明那些包不需要導入。

 

例如在我使用google-gwt servlet jar的時候。我需要導入這個包:

 

Bundle-ClassPath:\ .,\ lib/gwt-servlet.jar,\ lib/gson.jar -includeresource:\ lib/gwt-servlet.jar=gwt-servlet-2.8.0.jar,\ lib/gson.jar=gson-2.8.0.jar

 

但是卻需要額外聲明,這些包我不需要import

Import-Package: \ !com.google.gwt.xhr.client.*,\ !com.google.gwt.core.*,\ !com.google.gwt.dev.*,\ !com.google.gwt.i18n.*,\ !com.google.gwt.json.*,\ !com.google.gwt.junit.*,\ !com.google.gwt.thirdparty.*,\ !com.google.gwt.uibinder.*,\ !com.google.gwt.user.*,\ !com.google.gwt.util.*,\ !jsinterop.*,!javax.annotation.*,!javax.imageio.*,!javax.lang.model.*,\ !javax.tools.*,!javax.validation.*,!org.apache.*,!org.objectweb.*,\ !org.w3c.*,!sun.*,!junit.framework,\ *

其中!是不導入的意思。最後的*是指導入所需要並且在OSGi容器中能導入的。

Neil Jin 2017-01-07T13:52:59Z
Categories: CMS, ECM

译文:OSGi Module依赖

Liferay - Sat, 01/07/2017 - 03:48

原文作者:David H Nebinger

原文地址:https://web.liferay.com/web/user.26526/blog/-/blogs/osgi-module-dependencies

如有问题,欢迎在原文下面讨论,也欢迎在这里留言。

 

假设在Liferay DXP平台上开发module的时候,遇见了需要运行环境(runtime)的依赖的时候,该怎么办?

在这片简短的文章中,我会介绍几种方法...

假设你有一个module需要iText(和iText的依赖)作为依赖。这其实和module本身的功能关系不是很大,但是你现在有这个依赖,需要一种方法来使用它。

 

方法 1 - 放在全局目录下

这种方法最简单也最粗暴。所有在全局类加载器(比如tomcat的lib和lib/ext)中的类可以被所有类访问,包括Liferay OSGi容器。

但是全局的jar有全局的问题。不仅所需要的jar需要在全局目录,所有jar的依赖也需要在全局目录。并且全局类只有一个版本,其他的消费类无法使用不同的版本。

 

方法 2 - 让OSGi处理

 

这个是第二简单的方法,但是可能无法使用。如果你在module中声明一个运行环境的依赖,并且OSGi中有一个bundle可以满足依赖的话,module会使用使用这个依赖。

当你确认OSGi中依赖可以被使用的时候,这个方法就可以使用。因为这个方法是利用portal中已有的依赖,或者你之前已经部署到OSGi容器中的依赖(有些jar可能已经包含了OSGi bundle的信息,可以直接部署到容器中)。

例如,假设我们要声明iText依赖,虽然iText应该不会作为bundle已经部署到了OSGi中,所以如果依赖OSGi容器来使用iText很可能会出错的。现在仅是用作举例

使用build.gradle文件来声明运行环境依赖。这段代码是用来声明iText运行环境依赖的

 

runtime group: 'com.iowagie', name: 'itext', version: '1.4.8'

 

如果iText(和其依赖)已经成功的部署到OSGi容器中,通过运行环境依赖声明就可以在你自己的module中使用了。如果iText不可用,你的module就不会启动,并且会报错 -- 依赖无法满足。

 

方法 3 - 制作成一个超级胖子Module  

像那些巨型jar一样,巨型module会拥有所有依赖的类直接暴露在module jar中。

使用Gradle和BND很好实现。

在build.gradle中,你应该像方法2中一样声明运行环境依赖。

并且通过在bnd.bnd中包含所需的资源使module成为一个巨型module:

Include-Resource: @itext-1.4.8.jar

在这里引入依赖jar,一般在gradle下来依赖或者浏览maven库的时候都可以看到具体版本。

要注意的是,也需要引入依赖所以依赖的jar。例如,iText2.08依赖于BouncyCasle mail和prov,所以这些依赖也需要添加:

Include-Resource: @itext-2.0.8.jar,@bcmail-138.jar,@bcprov-138.jar

也需要在build.gradle中添加这些依赖,以便gradle引入这些jar。

如果使用zip工具打开module jar包的话,会看见所有依赖的jar会被解压,class文件会被直接放在module jar包中。

 

方法 4 - 在Module中引入整个jar  

最后的方法是在module中引入jar,和巨型module不一样,这个方法将整个jar包含到module jar中

和方法2,3相似的是,也需要在build.gradle中声明运行环境依赖。

引用jar是在bnd.bnd中完成的。

首先需要定义Bundle-ClassPath属性来引入module jar和其余的依赖jar。在下面的例子中,我指定iText jar会包含在module jar中:

 

Bundle-ClassPath:\ .,\ lib/itext.jar

这里我们不使用Include-Resource声明,而是使用-includeresource来-将jar引入到bundle中:

-includeresource:\ lib/itext.jar=itext-1.4.8.jar

在这里,我们将itext-1.4.8.jar包含到module中,保存为lib/itext.jar。itext-1.4.8是通过Gradle导入的运行环境依赖。

这种语法也支持通配符,可以有效利用build.gradle选择版本的特性。这个例子是用来包含任何版本的commons-lang:

-includeresource:\ lib/itext.jar=itext-1.4.8.jar,\ lib/commons-lang.jar=commons-lang=[0-9]*.jar

如果使用压缩软件打开module的jar文件的话,可以看到jar文件会在lib文件夹下。

 

总结

实际项目中应该使用哪种方法?和Liferay开发一样,因需而异。

全局方法适用于只需要一种版本的jar包并且需要用到大量的依赖的情况。例如,项目中有20个不同的module全部依赖于iText 1.4.8,这样,全局方法就是最好的选择。

第二种方法只用于依赖jar是OSGi bundle的情况。在这种情况下,你可以使用不同的版本,并且不用担心去编辑bnd文件。

第三种和第四种方法是最常用的放法。在上面这些情境下,你的依赖是包含在module中的,OSGi类容器中的类是不会被不同版本的ja“污染”的。并且,module也是不依赖于当前容器环境的,因为module自己已经包含了所有的依赖,运行环境也不需要为module事前准备依赖。

我个人很喜欢使用第四种方法,以为巨型jar在解压缩类的时候,可能会有路径上的交错(例如xml和配置文件)。第四种方法就不会有这样的问题。

 

希望你喜欢

 

译者补充: 在使用方法3,4的时候,OSGi容器会要求导入要引用jar的所有依赖,这样的结果是,需要导入无尽的包,因为依赖还有依赖,依赖还有依赖,子子孙孙无穷匮也。 所以,需要通过bnd.bnd来声明那些包在容器中不需要导入。 例如在我使用google-gwt servlet jar的时候。我需要导入这个包: Bundle-ClassPath:\ .,\ lib/gwt-servlet.jar,\ lib/gson.jar -includeresource:\ lib/gwt-servlet.jar=gwt-servlet-2.8.0.jar,\ lib/gson.jar=gson-2.8.0.jar   但是却需要额外声明,这些包我不需要import Import-Package: \ !com.google.gwt.xhr.client.*,\ !com.google.gwt.core.*,\ !com.google.gwt.dev.*,\ !com.google.gwt.i18n.*,\ !com.google.gwt.json.*,\ !com.google.gwt.junit.*,\ !com.google.gwt.thirdparty.*,\ !com.google.gwt.uibinder.*,\ !com.google.gwt.user.*,\ !com.google.gwt.util.*,\ !jsinterop.*,!javax.annotation.*,!javax.imageio.*,!javax.lang.model.*,\ !javax.tools.*,!javax.validation.*,!org.apache.*,!org.objectweb.*,\ !org.w3c.*,!sun.*,!junit.framework,\ * 其中!是不导入的意思。最后的*是指导入所需要并且在OSGi容器中能导入的。 Neil Jin 2017-01-07T08:48:20Z
Categories: CMS, ECM

Removing Panels from My Account

Liferay - Thu, 12/29/2016 - 23:11

So recently I was asked, "How can panels be removed from the My Account portlet?"

It seems like such a deceptively simple question since it used to be a supported feature, but my response to the question was that it is just not possible anymore.

Back in the 6.x days, all you needed to do was override the users.form.my.account.main, identification and/or miscellaneous properties in portal-ext.properties and you could take out any of the panels you didn't want the users to see in the my account panel.

The problem with the old way is that while it was easy to remove panels or reorganize panels, it was extremely difficult to add new custom panels to My Account.

With Liferay 7 and DXP, things have swung the other way.  With OSGi, it is extremely easy to add new panels to My Account.  Just create a new component that implements the FormNavigatorEntry interface and deploy it and Liferay will happily present your custom panel in the My Account.  See https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/form-navigator for information how to do this.

Although it is easy to add new panels, there is no way to remove panels.  So I set out to find out if there was a way to restore this functionality.

Background

In Liferay 7, the new Form Navigator components replaces the old portal properties setup.  But while there used to be three separate sets of properties (one for adds, one for updates and one for My Account), they have all been merged into a single set.  So even if there was a supported way to disable a panel, this would disable the panel from not only My Account but also from the users control panel, not something that most sites want.

So this problem actually points to the solution - in order to control the My Account panels separately, we need a completely separate Form Navigator setup.  If we had a separate setup, we'd also need to have a JSP fragment bundle override to use the custom Form Navigator rather than the original.

Creating the My Account Form Navigator

This is actually a simple task because the Liferay code is already deployed as an OSGi bundle, but more importantly the current classes are declared in an export package in the module's BND file.  This means that our classes can extend the Liferay classes without dependency issues.

Here's one of the new form navigator entries that I came up with:

@Component( immediate = true, property = {"form.navigator.entry.order:Integer=70"}, service = FormNavigatorEntry.class ) public class UserPasswordFormNavigatorEntryExt extends UserPasswordFormNavigatorEntry { private boolean visible = GetterUtil.getBoolean(PropsUtil.get( Constants.MY_ACCOUNT_PASSWORD_VISIBLE), true); @Override public String getFormNavigatorId() { return Constants.MY_ACCOUNT_PREFIX + super.getFormNavigatorId(); } @Override public boolean isVisible(User user, User selUser) { return visible && super.isVisible(user, selUser); } }

So first off our navigator entry extends the original entry, and that saves us a lot of custom coding.  We're using a custom portal property to disable the panel, so we're fetching that up front.  We're using the property setting along with the super class' method to determine if the panel should be visible.  This will allow us to set a portal-ext.property value to disable the panel and it will just get excluded.

The most important part is the override for the form navigator ID.  We're declaring a custom ID that will separate how the new entries and categories will be made available.

All of the other form navigator entries will follow the same pattern, they'll extend the original class, use a custom property to allow for disabling, and they'll use the special category prefix for the entries.

We'll do the similar with the category overrides:

@Component( property = {"form.navigator.category.order:Integer=30"}, service = FormNavigatorCategory.class ) public class UserUserInformationFormNavigatorCategoryExt extends UserUserInformationFormNavigatorCategory { @Override public String getFormNavigatorId() { return Constants.MY_ACCOUNT_PREFIX + super.getFormNavigatorId(); } }

For the three component categories we'll return our new form navigator ID string.

Creating the My Account JSP Fragment Bundle

Now that we have a custom form navigator, we'll need a JSP override on My Account to use the new version.

Our fragment bundle is based off the the My Account portlet, so we can use the following blade command:

blade create -t fragment -h com.liferay.my.account.web -H 1.0.4 users-admin-web-my-account

If you're using an IDE, just use the equivalent to create a fragment module from the My Account web module for the version currently used in your portal (check the $LIFERAY_HOME/work folder for the com.liferay.my.account.web folder as it includes the version number in your portal).

To use our new form navigator, we need to override the edit_user.jsp page.  This page actually comes from the modules/apps/foundation/users-admin/users-admin-web module from the Liferay source (during build time it is copied into the My Account module).  Copy the file from the source to your new module as this will be the foundation for the change.

I made two changes to the file.  The first change adds some java code to use a variable for the form navigator id to use, the second change was to the <liferay-ui:form-navigator /> tag declaration to use the variable instead of a constant.

Here's the java code I added:

// initialize to the real form navigator id. String formNavigatorId = FormNavigatorConstants.FORM_NAVIGATOR_ID_USERS; // if this is the "My Account" portlet... if (portletName.equals(myAccountPortletId)) { // include the special prefix formNavigatorId = "my.account." + formNavigatorId; }

We start with the current constant value for the navigator id.  Then if the portlet id matches the My Account portlet, we'll add our form navigator ID prefix to the variable.

Here's the change to the form navigator tag:

<liferay-ui:form-navigator backurl="<%= backURL %>" formmodelbean="<%= selUser %>" id="<%= formNavigatorId %>" markupview="lexicon"> </liferay-ui:form-navigator>

Build and deploy all of your modules to begin testing.

Testing

Testing is actually pretty easy to do.  Start by adding some portal-ext.properties file entries in order to disable some of the panels:

my.account.addresses.visible=false my.account.additional.email.visible=false my.account.instant.messenger.visible=false my.account.open.id.visible=false my.account.phone.numbers.visible=false my.account.sms.visible=false my.account.social.network.visible=false my.account.websites.visible=false

If your portal is running, you'll need to restart the portal for the properties to take effect.

Start by logging in and going to the Users control panel and choose to edit a user.  Don't worry, we're not editing, we're just looking to see that all of the panels are there:

Next, navigate to My Account -> Account Settings to see if the changes have been applied:

Here we can see that the whole Identification section has been removed since all of the panels have been disabled.  We can also see that password and personal site template sections have been removed from the view.

Conclusion

So this project has been loaded to GitHub: https://github.com/dnebing/my-account-override  Feel free to clone and use as you see fit.

It uses properties in portal-ext.properties to disable specific panels from the My Account page while leaving the user control panel unchanged.

There is one caveat to remember though.

When we created the fragment, we had to use the version number currently deployed in the portal.  This means that any upgrade to the portal, to a new GA or a new SP or FP or even hot fix may change the version number of the My Account portlet.  This will force you to come back to your fragment bundle and change the version in the BND file.  In fact, my recommendation here would be to match your bundle version to the fragment host bundle version as it will be easier to identify whether you have the right version(s) deployed.

Otherwise you should be good to go!

Update: You can eliminate the above caveat by using a version range in your bnd file.  I changed the line in bnd.bnd file to be:

Fragment-Host: com.liferay.my.account.web;bundle-version="[1.0.4,2.0.0)"

This allows your fragment bundle to apply to any newer version of the module that gets deployed up to 2.0.0.  Note, however, that you should still compare each release to ensure you're not losing any fixes or improvements that have been shipped as an update.

David H Nebinger 2016-12-30T04:11:41Z
Categories: CMS, ECM

Overriding Module JSP in Liferay 7 using Liferay IDE

Liferay - Wed, 12/28/2016 - 05:57

With the release of Liferay IDE 3.1 M1 ,I noticed one more interesting feature that developers might be looking for, is that jsp of the OOTB module JSPs  can be modified using Liferay Module Fragment project in Liferay IDE 3.1 M1. One approach to override module JSPs is mentioned on page.

As described below , JSPs fragment can also be generated using Liferay IDE 3.1 M1.

Create new module fragment project.

 

Configure Liferay Runtime environment and select it as shown below.

As next step, now select the Host OSGI bundle.

After selecting the Host OSGI bundle, need to select the jsp  you want to override in the selected module.

So after selecting Host OSGI bundle and file that need to override, it is almost done. Click finish to proceed further, it will create Module Fragment Project structure. In the generated project structure , if we see file blog-fragment/bnd.bnd .

Following two entries are important to add that is mentioned on the page.

Fragment-Host: com.liferay.blogs.web;bundle-version="2.0.0"

In the generated module fragment project , selected jsp is also added that can be modiefied.

 

 

Now Build the above created module fragment project using the build Gradle task. 

It will generate the packaged JAR in blog-fragment/build/lib folder. Deploy the generated JAR to see the changes.

Sushil Patidar 2016-12-28T10:57:07Z
Categories: CMS, ECM

Liferay 7 theme development with IDE

Liferay - Wed, 12/28/2016 - 04:40

Liferay IDE 3.1 M1 has been released. Previously i explored Liferay 7 theme development using theme generator as expalined on page. Since than I was curious to do it through Liferay IDE that seems to more convenient for developers. In Liferay IDE 3.1 M1, I have noticed that theme project templates are added. Explaining steps so that it might be helpful for the community.

Follow the below steps to create themes in Liferay 7 using IDE 3.1 M1.

Step-1:-

Go to Liferay workspace and create Liferay Module Project as shown in below. Select Project Template for theme. 

After creating theme module project. Project structure is created to develop custom theme.

At this point if you look at the project structure, there is no build folder generated.

Step-2:-

Now build theme using following Gradle Task. 

It will generate theme files in the build folder as shown below.

This files are generated from classic styled theme, if you want to override files just place them in the first-theme/src/main/webapp folder.

Like if you want to override portal_normal.ftl, create folder templates in first-theme/src/main/webapp/ as follows and place portal_normal.ftl.

 

Step-3:- Build theme using following gradle task.

 

It will package theme in war in the  first-theme/build/libs folder. Deploy this WAR file to see the custom changes. 

 

Sushil Patidar 2016-12-28T09:40:06Z
Categories: CMS, ECM

Extending Liferay OSGi Modules

Liferay - Tue, 12/20/2016 - 23:59

Recently I was working on a fragment bundle for a JSP override to the message boards and I wanted to wrap the changes so they could be disabled by a configuration property.

But the configuration is managed by a Java interface and set via the OSGi Configuration Admin service in a completely different module jar contained in an LPKG file in the osgi directory.

So I wondered if there was a way to weave in a change to the the Java interface to include my configuration item in a concept similar to the plugin extending a plugin technique.

And in fact there is and I'm going to share it with you here...

Creating The Module

So first we're going to be building a gradle module in a Liferay workspace, so you're going to need one of those.

In our modules directory we're going to create a new folder named message-boards-api-ext for containing our new module.  Actually the name of the folder doesn't matter too much so feel free to follow your own naming standards.

We need a gradle build file, and since we're in a Liferay workspace, our build.gradle file is pretty simple:

dependencies { compileOnly group: "biz.aQute.bnd", name: "biz.aQute.bndlib", version: "3.1.0" compileOnly group: "com.liferay", name: "com.liferay.portal.configuration.metatype", version: "2.0.0" compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "2.0.0" compileOnly group: "javax.servlet", name: "javax.servlet-api", version: "3.0.1" compileOnly group: "org.osgi", name: "org.osgi.core", version: "5.0.0" compile group: "com.liferay", name: "com.liferay.message.boards.api", version: "3.1.0" } jar.archiveName = 'com.liferay.message.boards.api.jar'

The dependencies mostly come from the build.gradle file from the module from the Liferay source found here: https://github.com/liferay/liferay-portal/blob/master/modules/apps/collaboration/message-boards/message-boards-api/build.gradle

We did add as a compile option the module that we're building a replacement for, in this case the com.liferay.message.boards.api module.

Also we are specifying the archive name that we are building that excludes the version number.  We're specifying the archive name so it matches the specifications from the Liferay override documentation: https://github.com/liferay/liferay-portal/blob/master/tools/osgi-marketplace-override-README.markdown

We also need a bnd.bnd file to build our module:

Bundle-Name: Liferay Message Boards API Bundle-SymbolicName: com.liferay.message.boards.api Bundle-Version: 3.1.0 Export-Package:\ com.liferay.message.boards.configuration,\ com.liferay.message.boards.display.context,\ com.liferay.message.boards.util.comparator Liferay-Releng-Module-Group-Description: Liferay-Releng-Module-Group-Title: Message Boards Include-Resource: @com.liferay.message.boards.api-3.1.0.jar

The bulk of the file is going to come directly from the original: https://github.com/liferay/liferay-portal/blob/master/modules/apps/collaboration/message-boards/message-boards-api/bnd.bnd.

The only addition to the file is the Include-Resource BND declaration.  As I previously covered in my blog post about OSGi Module Dependencies, this is the declaration used to create an Uber Module.  But for our purposes, this actually provides the binary source for the bulk of the content of our module.

By building an Uber Module from the source module, we are basically going to be building a jar file from the exploded original module jar, allowing us to have the baseline jar with all of the original content.

Finally we need our source override file, in this case we need the src/main/java/com/liferay/message/boards/configuration/MBConfiguration.java file:

package com.liferay.message.boards.configuration; import aQute.bnd.annotation.metatype.Meta; import com.liferay.portal.configuration.metatype.annotations.ExtendedObjectClassDefinition; /** * @author Sergio González * @author dnebinger */ @ExtendedObjectClassDefinition(category = "collaboration") @Meta.OCD( id = "com.liferay.message.boards.configuration.MBConfiguration", localization = "content/Language", name = "mb.configuration.name" ) public interface MBConfiguration { /** * Enter time in minutes on how often this job is run. If a user's ban is * set to expire at 12:05 PM and the job runs at 2 PM, the expire will occur * during the 2 PM run. */ @Meta.AD(deflt = "120", required = false) public int expireBanJobInterval(); /** * Flag that determines if the override should be applied. */ @Meta.AD(deflt = "false", required = false) public boolean applyOverride(); }

So the bulk of the code comes from the original: https://github.com/liferay/liferay-portal/blob/master/modules/apps/collaboration/message-boards/message-boards-api/src/main/java/com/liferay/message/boards/configuration/MBConfiguration.java

Our addition is the new flag value.

Now if we had other modifications for other classes, we would make sure we had the same paths, same packages, same class names, we would just have our changes in on top of the originals.

We could even introduce new packages and classes for our custom code.

Building The Module

Building is pretty easy, we just use the gradle wrapper to do the build:

$ ../../gradlew build

When we look inside of our built module jar, this is where we can see that our change did, in fact, get woven into the new module jar:

We can see from the highlighted line from the compiled class that our jar definitely contains our method, so our build is good.  We can also see the original packages and resources that we get from the Uber Module approach, so our module is definitely complete.

Deploying The Module

Okay, so this is the ugly part of this whole thing, deployments are not easy.

Here's the restrictions that we have to keep in mind:

  1. The portal cannot be running when we do the deployment.
  2. The built jar file must be copied manually to the $LIFERAY_HOME/osgi/marketplace/override folder.
  3. The $LIFERAY_HOME/osgi/state folder must be deleted.
  4. If you have changed any web-type file (javascript, JSP, css, etc.) you should delete the relevant folder from the $LIFERAY_HOME/work folder.
  5. If Liferay deployes a newer version than the one declared in our bundle override, our changes may not be applied.
  6. Only one override bundle can work at a time; if someone else has an override bundle in this folder, your change will step on theirs and this may not be a option (Liferay may distribute updates or hot fixes as module overrides in this fashion).
  7. Support for $LIFERAY_HOME/osgi/marketplace/override was added in later LR7CE/DXP releases, so check that the version you are using has this support.
  8. You can break your portal if your module override does bad things or has bugs.

Wow, that is a lot of restrictions.

Basically we need to copy our jar manually to the $LIFERAY_HOME/osgi/marketplace/override folder, but we cannot do it if the application server is running.  The $LIFERAY_HOME/osgi/state folder should be whacked as we are changing the content of the folder.  And the bundle folder in $LIFERAY_HOME/work may need to be deleted so any cached resources are properly cleaned out.

For this change, we copy the com.liferay.message.boards.api.jar file to $LIFERAY_HOME/osig/marketplace/override folder and delete the state folder when the application server is down, then we can fire up the application server to see the outcome.

Conclusion

We can verify the change works by navigating to the Control Panel -> System Settings -> Collaboration -> Message Boards page and viewing the change:

Be forewarned, however!  Listen when I emphasize the following:

Pay special attention to the restrictions on this technique!  This is not a "build, deploy and forget it" technique as each Liferay upgrade, fix pack or hot fix can easily invalidate your change, and every deployment requires special handling. You can seriously break Liferay if you deliver bad code in your module override, so test the heck out of these overrides. This should not be used in lieu of supported Liferay methods to extend or replace functionality (JSP fragment bundles, MVC command service overrides, etc.), this is just intended for edge cases where no other override/extension option is supported.

In other words:

 

David H Nebinger 2016-12-21T04:59:04Z
Categories: CMS, ECM

To add custom organizations in Liferay 6.2

Liferay - Tue, 12/20/2016 - 01:53

There may be a requirement to add custom organizations instead of Regular Organization & Location.

To acheive this we need to add the below properties in portal.ext.properties

## For add custom organizations

organizations.types=regular-organization,location,custom-organization

organizations.rootable[regular-organization]=true

organizations.rootable[custom-organization]=true

organizations.children.types[regular-organization]=regular-organization,location,custom-organization

 

then restart the server

Login as Admin and Control Pannel -> Users and Organizations

Click on  'Type' drop down we can find a new organization as 'custom-organization'.

 

om prakash 2016-12-20T06:53:20Z
Categories: CMS, ECM

在DXP中使用公共参数支持IPC

Liferay - Fri, 12/16/2016 - 21:35

本文在于讨论如何在Liferay DXP(Liferay 7)中使用公共参数(public render parameter)支持IPC。

关键点:

    在6.2以前的,我们需要在portlet.xml中声明公共参数,但是在OSGi时代,我们需要在Component中进行声明:

     "javax.portlet.supported-public-render-parameter=message"

     其中“message”是公共参数的名称。

     声明之后,就可以像使用普通render parameter一样使用这个参数了。

     在Jsp中创建参数时可以这样写:

    <portlet:renderURL var="senderURL">

        <portlet:param name="message" value="Prove you can receive me" />     </portlet:renderURL>       可以通过这样的方式获取参数的值:     renderRequest.getParameter("message");       附件中是一个可以使用的样例,安装之后可以在Sample分类下找到portlet。     点击下载项目源码 点击下载jar直接部署可以测试 Neil Jin 2016-12-17T02:35:50Z
Categories: CMS, ECM

Flexible Liferay 7 - Tomcat Setup

Liferay - Fri, 12/16/2016 - 05:37
Flexible Liferay 7 - Tomcat Setup The challenge

If you want to run Liferay 7 on Tomcat using the bundle provided by Liferay or packages provided in your Linux distribution are convenient ways to get Liferay up and running fast.

In many cases you may however want to have a better control on which Tomcat version you are running on and also want to have an easy upgrade path. You may also want to run multiple Tomcat instances in one server like one for Liferay and one for SOLR and want to reduce administrative tasks and avoid installing Tomcat multiple times. If you are a developer you could also want to run different versions of the portal and even run the portal on different JREs in the same server. It would also be convenient to be able to setup database easily for the Tomcat instances.

Last but not least the setup created by the scripts provided here shouldn’t be anything proprietary or dependent of the scripts.

About this setup

To fulfill these requirement this setup aims at the following objectives:

  • Automation scripts provided here should be readable and easily modifiable
  • Installation structure should be simple and readable
  • Tomcat installation folder should remain unmodified if possible
  • Invidual Tomcat instances should be easily configurable
  • There should be a fast way to create new Tomcat instances from templates
  • Database creation and configuration for a new Tomcat Liferay instance should be easy

By default this setup creates following structure:

There are three scripts in this package:

  • install-environment.sh: creates Tomcat environment, sets up MySQL and Java
  • create-liferay-instance.sh: creates a new Tomcat instance based on defined template
  • manage-instance.sh: starts and stops instances

This setup has been tested in Ubuntu Linux 16.04 LTS.

Yes, the setup and scripts here are not a Swiss knife solution as they are for example relying on MySQL. Hopefully someone will find them useful anyways!

The scripts and more instructions: https://github.com/peerkar/multi-instanced-tomcat-liferay-setup

 

Petteri Karttunen 2016-12-16T10:37:36Z
Categories: CMS, ECM

Legacy Data Base (Informix 11.5 RDBMS)connection & retrieval of data in Liferay 6.2 CE

Liferay - Thu, 12/15/2016 - 23:58

Informix Dynamic Server

Informix Dynamic Server, also known as IDS, is an extensible Relational Database Management System originally developed by Informix Software Inc. IDS is now part of the IBM Software Group database portfolio.

Use the below link to download Informix 11.5 server and need to register.

https://www-01.ibm.com/marketing/iwm/iwm/web/preLogin.do?source=ifxids

How to Install and Configure Informix Dynamic Server ...?

Please refer the link  http://www.supermap.com/EN/online/Deskpro%206.0/SDTechTheme/ExpressHtml/DataSources_Informix.htm#Configuring

once the configuration completed we need to create a database "matrade". Create tables r_state & company (for table columns refer below service.xml) within matrade dbase to carry out below example. Insert some data in both tables. You can refer IBM Informix manual to create a database and table.

How to Configuring Informix in liferay ...?

1)  We need ifxjdbc.jar file and place it in 'tomcat/webapps/ROOT/WEB-INF/lib' so that accessible by all portlet. you can get this from https://www-01.ibm.com/marketing/iwm/tnd/search.jsp?go=y&rs=ifxjdbc

2)  Make the following entries inside the "portal-setup-wizard.properties" under PORTAL_HOME for our custom Informix data base.

jdbc.custom.default.driverClassName=com.informix.jdbc.IfxDriver

jdbc.custom.default.url= jdbc:informix-sqli://host-name:port-number/dbName:INFORMIXSERVER=serverName

jdbc.custom.default.username=username of server instance jdbc.custom.default.password=password of server server

Note:

host-name - server name or IP Address of the remote server

port-number - port number of informix server

dbName - name of the database going to be connect

serverName - name given to the server during configuration

username & password  - is the one given during configuring Informix

 

Ex:

########### Liferay Portal Informix Local Database Configuration ########## jdbc.custom.default.driverClassName=com.informix.jdbc.IfxDriver

jdbc.custom.default.url=jdbc:informix-sqli://localhost:9088/matrade:INFORMIXSERVER=ol_qqq

jdbc.custom.default.username= *******

jdbc.custom.default.password= *********

now restart the server.

 

3)  Inside the portlet create a new file "ext-spring.xml" inside of "WEB-INF/src/META-INF" and paste the following content.

<?xml version="1.0"?>

<beans default-destroy-method="destroy" default-init-method="afterPropertiesSet"

       xmlns="http://www.springframework.org/schema/beans"

       xmlns:aop="http://www.springframework.org/schema/aop"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:schemaLocation="http://www.springframework.org/schema/aop

       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

       http://www.springframework.org/schema/beans

       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

 

       <bean id="customDataSource"

              class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">

              <property name="targetDataSource">

                     <bean class="com.liferay.portal.dao.jdbc.util.DataSourceFactoryBean">

                           <property name="propertyPrefix" value="jdbc.custom.default." />

                     </bean>

              </property>

       </bean>

 

       <bean id="customHibernateSessionFactory"

              class="com.liferay.portal.kernel.spring.util.SpringFactoryUtil"

              factory-method="newBean">

              <constructor-arg

                     value="com.liferay.portal.spring.hibernate.PortletHibernateConfiguration" />

              <constructor-arg>

                     <map>

                           <entry key="dataSource" value-ref="customDataSource" />

                     </map>

              </constructor-arg>

       </bean>

       <bean id="customSessionFactory"

              class="com.liferay.portal.kernel.spring.util.SpringFactoryUtil"

              factory-method="newBean">

              <constructor-arg

                     value="com.liferay.portal.dao.orm.hibernate.PortletSessionFactoryImpl" />

              <constructor-arg>

                     <map>

                           <entry key="dataSource" value-ref="customDataSource" />

                           <entry key="sessionFactoryClassLoader" value-ref="portletClassLoader" />

                           <entry key="sessionFactoryImplementor"

                                         value-ref="customHibernateSessionFactory" />

                     </map>

              </constructor-arg>

       </bean>

 

How to retrieve Informix data using Custom SQL statement ...?

Define a new entity 'CompanyExt' inside service.xml, mapped to informix data source and not the default one. table="company" & table="r_state" refers to the tables in Informix DB. The additional three attributes data-source, tx-manager and session-factory are mandatory. save file and generate the service layer.

Below is "service.xml" file entry.

<entity name="CompanyExt" local-service="true" remote-service="true"

              data-source="customDataSource" session-factory="customSessionFactory"  table="company">

              <column name="cmpy_id" type="int" primary="true" />

              <column name="reg_num" type="int" />

              <column name="company_name" type="String" />

              <column name="state" type="int" />

<entity>

 

<entity name="State" local-service="true"  remote-service="true"

              data-source="customDataSource" session-factory="customSessionFactory"  table="r_state">

       <column name="state_code" type="int" primary="true"></column>

       <column name="state_desc" type="String"  ></column>

</entity>

Create "default.xml" under "WEB-INF/src/custom-sql" (create the folder with the same name) and put the follwing custom SQL.

<?xml version="1.0" encoding="UTF-8"?>

       <custom-sql>

              <sql id = "com.myexport.services.service.persistence.CompanyExtFinderImpl.fetchCompanyByState">

                     <![CDATA[

                     select * from company  where state=? ;

                     ]]>

              </sql>

       </custom-sql>

This file will have all the queries in simple SQL format in the form of key-value pairs. The key is the id that can be anything. The value is the actual query embedded within . If you look the value it is nothing but a simple SQL select statement.

Create a new finder implementation class “CompanyExtFinderImpl” inside “WEB- INF/src/com /slayer/service/persistence”. While creating this class make it implement “CompanyExtFinder” interface and extend “BasePersistenceImpl”.

Below is the 'CompanyExtFinderImpl.java' file

 

public class CompanyExtFinderImpl extends BasePersistenceImpl implements CompanyExtFinder{

public static String FETCH_COMPANY_BY_STATE=CompanyExtFinderImpl.class.getName()+".fetchCompanyByState";

@SuppressWarnings("unchecked")

public List fetchCompanyByState(int state){

// 1. Open an ORM session Session session = openSession();

// 2. Get SQL statement from XML file with its name

String sql = CustomSQLUtil.get(FETCH_COMPANY_BY_STATE);

System.out.println("The Query is >>>>>>>>>"+sql);

// 3. Transform the normal query to HQL query

SQLQuery query = session.createSQLQuery(sql);

// 4. Add the actual entity to be searched

query.addEntity("CompanyExt", CompanyExtImpl.class);

// 5. Replace positional parameters in the query

QueryPos queryPos=QueryPos.getInstance(query);

queryPos.add(Integer.toString(state));

// 6. Execute query and return results.

return (List<CompanyExt>query.list();

}

}

 

Make all the necessary imports required by the new code.

Update “CompanyExtLocalServiceImpl” with the below method to invoke our new custom finder.

 

public List fetchCompanyByState(int state) {

List companyExts=null;

companyExts = CompanyExtFinderUtil.fetchCompanyByState(state);

return companyExts;

}

Make the imports for LMSBookFinderUtil.

Below is the code in view.jsp to retrieve company details as per state code.

 

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

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>

<%@page import="com.myexport.services.service.StateLocalServiceUtil"%>

<%@page import="com.myexport.services.model.State"%>

<%@page import="com.myexport.services.service.CompanyExtLocalServiceUtil"%>

<%@page import="com.myexport.services.model.CompanyExt"%>

<%

List states=StateLocalServiceUtil.getStates(-1, -1);

for(State state:states){

List companyExts=CompanyExtLocalServiceUtil.fetchCompanyByState(state.getState_code());

if(companyExts!=null){

for(CompanyExt companyExt:companyExts){ %>

<table>

<thead>

<tr>

<th>Company Id</th>

<th>Register Number</th>

<th>Company Name</th>

</tr>

</thead>

<tr>

<td><%=companyExt.getCmpy_id()%></td>

<td><%=companyExt.getReg_num()%></td>

<td><%=companyExt.getCmpy_id()%></td>

</tr>

</table>

<%}}} %>

Once all done deploy the portlet and verify the result.

 

 

 

 

om prakash 2016-12-16T04:58:26Z
Categories: CMS, ECM

Making portlet support public render parameter in DXP

Liferay - Tue, 12/13/2016 - 03:31

This is the way how to make IPC through public render parameter in Liferay DXP(Lfieray 7).

Key point:

     You need to add a supported render parameter in all portlet's Component Annotation.

     "javax.portlet.supported-public-render-parameter=message"

     The "message" is the public render parameter name.

    After you have done this you can use this parameter as a regular render parameter in the portlet. 

    In your link you can add the parameter like this:

    <portlet:renderURL var="senderURL">

        <portlet:param name="message" value="Prove you can receive me" />     </portlet:renderURL>       You can receive the value like this:     renderRequest.getParameter("message");   Please check the attachment for a functional project. After the module is installed you can find the portlets under Sample category.   Click me to download Project source code. Click me to download compiled jar. Neil Jin 2016-12-13T08:31:26Z
Categories: CMS, ECM

Liferay IDE 3.1 Milestone 1 Released

Liferay - Mon, 12/12/2016 - 23:34

Hello all,

First off I wanted to let everyone know that we have released a new milestone for Liferay IDE 3.1 You can install it into your Eclipse using below updatesite below:

http://releases.liferay.com/tools/ide/latest/milestone/

For full list of download see this page.

Code Upgrade Tool

Its been awhile since we have released a new update to Liferay IDE, but it isn't because we haven't been building stuff :).  Actually we have been working hard on a new Code Upgrade Tool that will easy upgrades from Liferay Portal 6.2 to Liferay 7.0/DXP specifically helping developers upgrade projects to 7.0.  Since this new upgrade tool is brand new we are rolling it out in several milestones, with the first one having support for upgrading Liferay 6.2 Plugins SDK projects to 7.0 either using new Liferay Workspace based on new gradle plugins or legacy 7.0 Plugins SDK.

Integrated into the Code Upgrade Tool is a better way to find all of the places in your code that you need to migrate to 7.0 APIs.  We now search through your code as compared to our own published "Breaking Changes" list and find instances, mark them with Eclipse markers, where you were using those now broken API calls.  Then we either can fix it for you automatically or give you contextual documentation that will help you manually resolve the issue.

Maven Support

We now have new Maven support for new Liferay Module Project Wizard.  One of the newest project template types is the theme template which supports building themes using new maven plugins.   Along with the new maven plugins, new m2e project lifecycles have been added to seemlessly support new Liferay 7.0 maven plugins such as css-builder and theme-builder (more on those in a later blog)

Along with maven support we have added many new templates available from Blade CLI version 2.0 (more info on this in later blog post)

We have added back the "New Liferay Module Fragment" wizard that makes it easier to create OSGi fragments based on existing Liferay modules.

Gradle Dependency Help

If you have some code in one of your Liferay modules that needs to import a package from a Liferay module that is deployed to your server, but you aren't for sure which artifact and version that it comes from, we now offer a quick fix for those packages that come from Liferay and we can automatically add the correct gradle dependency for that.

Since Liferay developers can now write modular applications using OSGi, many developers will be writing new DS Components.  So we are trying to make this process easier with code assist and code templates for editing DS component classes.  More on both of these features will show up in future blog posts.

Updates and Feedback

Stay tuned for more updates regarding Code Upgrade Tool in Milestone-2 as we will be adding Maven support for Code Upgrade Tool (so that maven plugins can be more easily upgraded to 7.0)

If you run into any issues or have any suggestions please come find us on our community forums and ask a question, we are always around to try to help you out.

Good luck and let us here from you!

Gregory Amerson 2016-12-13T04:34:23Z
Categories: CMS, ECM

Migrate / Upgrade to LR 6.2 CE GA6 from LR 6.2 old CE releases

Liferay - Mon, 12/12/2016 - 05:40

Dear Liferay Folks ,

This blog is specially for those who are using Liferay 6.2 CE versions for their portals. CE releases are the once which are released by Liferay. Every new CE release includes code fixings and further improvements in addition to previous version release.

Here is the Liferay CE version release process

Now one of my client was using Liferay 6.2 CE GA1 for his portal and was facing multiple issues regarding memory, performance and other Liferay OOTB code issues. The big reason to worry was memory and performance related issues. Everyday we were getting our server down with java.lang.OutOfMemoryError: Java heap space exception. We all most tried all points mentioned in below article of Liferay 6.2 Performance tunning. The good news is I was able to get my portal stable for more then one day but again it was failing with the same Out of heap space exception every second day. We analyzed heap dumps and also found there are couple of LPSs reported in JIRA regarding Memory and performance.

Finally, we planned to migrate from Liferay 6.2 GA1 to Liferay 6.2 GA6.

Below are the steps we followed as part of migration activity:
Environment Details : AppServer : jboss-as-7.2.0
Require resources : liferay-portal-6.2-ce-ga6-20160112152609836.war, liferay-portal-dependencies-6.2-ce-ga6-20160112152609836.zip

1. Back UP Database ,data folder and portal-ext.properties file [so that you can revert your changes]
2. Stop LR & remove Hook and theme, ext & ROOT.war [as we were using Jboss 7.2 in case of tomcat you could refer TOMCAT_HOME/webapps/ROOT]
3. Copy dependency jars to JBOSS_HOME\modules\system\layers\base\com\liferay\portal\main or TOMCAT_HOME\lib\ext
4. Create folder ROOT.war and extract liferay-portal-6.2-ce-ga6-20160112152609836.war to standalone/deployments/ROOT.war/ [or TOMCAT_HOME/webapps/ROOT]
5. Create file ROOT.war.dodeploy [for jboss only]
6. Remove tmp under /standalone [for tomcat remove work/ and temp/]
7. Add portal-ext.properties file at right location [in jboss ROOT.war/web-inf/classes]
8. Start the server
9. Deploy hook, ext and theme again. [NOTE : Don't forget to re-generate plugins wherever you find api changes or else one may end up with exceptions]
10. If you have trouble getting contents, try Re-indexing under server administration.

Post version migration you can go in to server administration and find upgraded Liferay version [in my case it was Liferay Portal Community Edition 6.2 CE GA6 (Newton / Build 6205 / January 6, 2016)], you can also check the same in release_ table.

After migration activity we've done testing and found everything is working fine.

We ran JMeter scripts with 400 threads in 200 seconds and the results says the average response time is improved. Also performed java heap dump analysis, I did not found major difference in total number of instance creation but yes memory space allocation was decreased post migration.

Apart from these we also has code fixes of around 450 issues reported with earlier 6.2 CE releases. Further we leveraged Known Vulnerability fixes as well.

From 457 reported issues we've got good memory and performance results with fixes of below bugs.
LPS-54758     Layout objects are stored in session creating a lot of memory and traffic use
LPS-55106     Too long PortletPreferences XML can cause OutOfMemoryError
LPS-46754     OutOfMemoryError when documentum FileEntry is exported
LPS-58121     GZipFilter is not sufficiently protecting set operations on the contentLength resulting in massive timed waits in the browser
LPS-43679     HTTP header parsing errors when viewing related web content articles multiple times
LPS-44236     Slow performance of AdvancedPermissionChecker#getUserBag() when a user is a member of several groups
LPS-54590     ServiceBuilder filterFindBy queries are not performant
LPS-55602     Exclude article content from keyword search to improve performance

So, this is all how we migrated to latest Liferay 6.2 CE release.

Hope this may also help other folks too.

Best Regards,
Vishal Panchal

Liferay Consultant

LinkedIn

Skype : vishalpanchal22

 

Vishal Panchal 2016-12-12T10:40:40Z
Categories: CMS, ECM

Devcon 2016: The Wild Wild West

Liferay - Fri, 12/09/2016 - 10:55

Once again: Devcon is over (actually, for quite a while now) and it's time to look back. If only because the Recap site is public. You can now watch the video recordings of presentations that you've missed, download slides and go through everything again.

Just like last year, we've started with the Unconference on Monday (day 0). Also, like last year, the Unconference was totally sold out, more than a month before the event. According to some, it was the most productive day of the conference, if only because everybody who wants to gets to speak up. Make sure to sign up in time for the next Unconference, so that you're experiencing the magic first hand.

Unlike last year, we've seen the incarnation of a remarkable and important new component of the event: Modconf. This is a new conference-within-a-conference, dedicated to Java modularity and not limited to Liferay. This parallel event was the reason for keynotes on day 1 (Tuesday) that were unusual and unexpected for Liferay-folks that expected a pure Devcon/Liferay experience. It was also the reason why we had more attendees on Tuesday than on Wednesday, because it was possible to book just the Modconf track on a single day. And it was one of the main causes to get an OSGi luminary like Peter Kriens for the keynote.

Did I mention the Wild Wild West? Conference Parties are fun - and this one particular so. Bullriding and other activities, all themed around the Wild West topic, were this year's party highlight.

Thank you to all participants, sponsors and in especially the organizing team who invested great effort (with an even greater outcome) for making this the inspiring event that it was. For me, these are the most intense working days of the year, but also the most rewarding ones.

If you already know that you're going to attend next year's Devcon: There's a special "I trust you" rate (for super-early-birds), which will give you the lowest possible price for next year's Devcon. Speaking of 2017, you're probably curious to know where and when Devcon will be next year - well, here's the answer.

Olaf Kock 2016-12-09T15:55:08Z
Categories: CMS, ECM

Liferay Karaf compatibility layer

Liferay - Fri, 12/09/2016 - 05:45
Hello Liferay Community,   Christmas is coming soon and that means you probably expect your well deserved (you've been good community members, haven't you?) present from Liferay's community! So I decided to make you one! A brand new and shiny Karaf compatibility layer for Liferay 7!    I know, those of you who know Karaf are now very excited! Yes remote SSH shell is there and you can now install and manage features in Liferay! Enjoy! And please send feedback!   I also know some of you have no idea what am I talking about :) Let me give you a brief explanation. Karaf is a a lightweight, powerful, and enterprise ready OSGi based container. It comes with many great features, such as dynamic configuration (which btw Liferay also has), provisioning applications, remote shell via SSH, JMX management, security layer for services and commands, instances management, ... This compatibility layer brings some of those things into Liferay:   Oh and there is already an answer to the "Wait, there is Gogo shell, why install another one?" question :)   Now go ahead, open you present, play with it and let me know how do you like it!  Milen Dyankov 2016-12-09T10:45:26Z
Categories: CMS, ECM

Layout creation in liferay 7

Liferay - Fri, 12/09/2016 - 01:33

Layouts in liferay 7 can be created by using theme generator. So if you want to create layout make sure that you have installed theme generator and other necessary plugins.

 

If you have not installed, then please follow the steps in my previous post

"Theme creation in liferay 7"

 

For creating a layout, open command prompt & navigate to the directory where you want your layout to be placed and run command : yo liferay-theme:layout


Theme generator will ask you for layout name, layout id and version. Give the respective values.

                       

 

Here i am creating 1-2-3 layout (3rows(1column-2columns-3columns))

 

Theme generator would ask for number of columns in 1st row and column width for each, enter the values.

 

Then you can see options to add, insert, remove row and finish layout, if you are fine with the entered columns and column width for the 1st row then go for Add row option, if not choose other appropriate ones.

           

 

Like wise follow the steps.

                               

                                       

 

Once done you can select Finish layout.

                                 

Now it will ask your path for tomcat directory and URL for your development site, provide the details.

 

Now you can build and deploy your layout using gulp commands.

  • gulp build
  • gulp deploy                      

 

 

Your layout is now deployed, 

                 

gulnaaz Shaik 2016-12-09T06:33:02Z
Categories: CMS, ECM
Syndicate content