Create an upgrade process in 6.2
Recently I've been working in some new features regarding to internacionalization the name and description of DLFileEntryType entity. I create all the logic and everithing was fine. Everthing went smoothly.
Due I was changing a DB table I had to create an upgrade process and the things became a litle bit hard (it's my very fist time creating an upgrade)... Why? Because I found an absolute lack of updated documentation about this kind of process.
It's true that I found a few wikis but it was a little messy (It was very funny to see five core engineers in the LA office triying to decode the [obsolete] documentation, true story...) So I've decided to create my fist blog entry regarding this.
But first of all... What is an upgrade process??
What we try to do in a upgrade process is guarantee that Liferay can upgrade from any previous version to any newer version.
We can see this in the following example.
I'm going to explain (based in the develop I made) the whole process, explaining how did I upgrade the DLFileEntryType entity by adding a new column called fileEntryTypeKey and changing the name and the description columns introducing localization properties.
Step 1 - Modify an entityThe first thing to do is to perfome all the required changes in the entity. It will give you the basis for the rest of the process. Not very much to explain, edit the service.xml ...
...Then run...
... and modifiy the Impl classes you need. Nothing special
Step 2 - Change .ftl if neededIf the entity has some default objects (i.e. DLFileentryType has 5 default types) maybe you'll need to change its .ftl file :
Step 3 - Create some UpgradeProcess classesGo to the proper version UpgradeProcess[XXX].java file (for us it's UpgradeProcess_6_2_0.java) and search for the right Upgrade[XXX].java (in this case is UpgradeDocumentLibrary). In this class (wich extends UpgradeProcess) you must introduce and override the doUpgrade() method like this:
As you can see we are directly using pure sql to perform the database upgrade. This clauses are surrounded by a try…catch that calls the method upgradeTable(few params) if something goes wrong...
Let's see that method deeply:
In there we are creating an UpgradeTable.java instance and we pass some values regarding the table we are modifiying. We get this values from an autogenerated class called XXXTable.java (DLFileEntryTypeTable.java for us).
Step 4 - Create the [XXX]Table classCreate this class is as simple as make its skeleton, modify portlet-model-hints.xml to define the configuraiton of the columns...
...and then run...
This is the generated class:
Step 5 - Create some logic to format and persist the current dataThe last method that we can see in doUpgrade() is:
Here we are getting the previous values and we pass them to...
...where we will reuse them in the modified table.
Step 6 - Regenerate all the service and TEST!This is the final step. All you got to do:
VERY IMPORTANT!!Run
Doing this you could be sure you are not breaking the default data.
And that's all!!!
Roberto Díaz 2013-05-16T23:27:17ZSales and Marketing Friction Points [Infographic]
Sales and marketing have to work together effectively. Your revenue depends on it. But as we’ve seen from our recent survey of sales and marketing professionals, at many companies there’s a lot of friction between the two teams. In fact, one data point showed that 50% of sales teams are not satisfied with their Marketing relationship.
So, what’s the source of the challenge? A few weeks back Daniel Chalef looked at the common friction points that exist between the two teams. The article summarized five key marketing automation and sales enablement technologies that help. Here’s a handy infographic to visualize how to solve the friction points.
Managing Liferay through the Gogo shell
I have done a huge refactor for most of our OSGi related work, moving the majority of its components to the Liferay plugins SDK. Everything except the graphical admin UI is already in the master branch of the official repo so you can play with it; we would love to hear your feedback.
My goal with this post is to show you how create a new OSGi bundle in the plugins SDK using a practical example: extending the OSGi shell (we have spoken about it sometime ago). Let's try to do it:
Basic project structureCurrently there is no target in the SDK which allows you to create a bundle (I will push it soon) so you can use this example (or the other modules as http-service-shared or log-bridge-shared) as the basic skeleton for your tests:
As you can see, the structure is very simple; let my try to highlight the main OSGi related points:
- All the new OSGi plugins will be based in the great bnd tool . You can configure all your bundle requirement through the bnd.bnd file
- The build.xml of the plugin must import the build-common-osgi-plugin.xml build file: <import file="../../build-common-osgi-plugin.xml" />
As I have told you before I will include an Ant target to create this basic skeletons, but, until then, you need to do this by hand. Sorry about that :(.
Writing Gogo shell custom commandsAs we have stated at the beginning of the post, we are going to write a bunch of custom commands for the Gogo shell. As you will see, this is an extremely easy task.
This commands can be created using a simple OSGi service with a couple of custom properties. We will use the OSGi declarative services approach in order to register our commands (Liferay already includes an implementation of the Declarative Services specification in the final bundle, so you don't need to deploy it by yourself).
At this point, we are ready to write our first command: the ListUsersCommand:
The @Component annotation let us to define a new OSGi service in an extremely easy way. The Gogo commands are registered in the console using the properties osgi.command.function and the osgi.command.scope. The first one establishes the name of the namespace where the command will be allocated (in order to prevent name collisions) while the latter specifies the name of the command. It is important to note that the Declarative Service annotations I am using does not support inheritance, so everything you declare in a base class will not be inherited down in the hierarchy.
And, how do I write the implementation of my new command? You just need to write a new public method named as the value written in the osgi.command.function. If your command needs some argument you will need to specify as a parameter of your method (an the console will do the coercion of the basic types). In our example we are creating a usermanagment namespace, with a command called listByCompany which expects the companyId (long) as the unique parameter.
Easy, isn't it?
Consuming Liferay servicesI would like to highlight the implementation of the listByCompany command (I am sure you have already guessed the previous command retrieves all the users of a certain company).
In order to get all this info we need to call the corresponding method in the users service. We could do something like UserLocalServiceUtil.getCompanyUsers(companyId) but this is not a good approach, so we are to going to get all the benefits of having all the Liferay services as OSGi services. We just need to grab a reference to the UserLocalService bean:
@Reference public void setUserLocalService(UserLocalService userLocaService) { _userLocalService = userLocaService; } protected UserLocalService _userLocalService; Building and running the bundle Once we have written our command we need to build our final artifact: just type ant jar in the project folder and you will get the final jar file into the dist folder. Before deploying our new bundle let's connect to the Gogo shell in order to check which bundles we have already installed: As you see, we have already a bunch of bundles running but nothing about the new commands we are writing. What commands are currently available in the console? Just type help in the console Now we have to deploy our new bundle. To do that, we just need to copy it to the folder $liferay.home/data/osgi/deploy (it is the default folder, you can change it in the properties). You can use the deploy Ant task our just copy the folder into the previous folder. Once the bundle is deployed we should see it in the bundles list: Take a look to the last line; you will see our bundle has been deployed and it is, hopefully, running. Let's see which commands we do have available once our new bundle is already installed. Do you see the last two lines? These are the commands we have written (in this post we only have described one command, you can find the other one in the companion source code). So, if I type listByCompany ID_OF_A_COMPANY (mine is 10153) (since there is no collision I don't need to prefix the command with the namespace) you should get an output similar to this: Users of the company 10153 User default@liferay.comwith id 10157 User test@liferay.comwith id 10195 Along this post we have seen how we can extend the Gogo shell creating new commands, consuming Liferay services and building a basic OSGi bundle in the plugins SDK. It is not a big deal but I think it is a good starting point to get used to the new OSGi abilities. Hopefully I will be able to push some more complex examples in the near future. You can find the whole source code in the shared/gogo-commands-shared folder at my plugins repo. Miguel Pastor Olivar 2013-05-14T21:46:33ZMavenize Liferay Plugins SDK - Using Maven
Overview
When working with Liferay projects using Liferay IDE and Plugins SDK it becomes highly difficult to manage dependencies, as Liferay IDE or Plugins SDK by default uses Ant for building and deploying, though Liferay does support Maven based Plugins but as a seasoned Liferay Developer we will be inclined to use Ant preferred to Maven.
The problem rather I call it a difficulty arises when,
- The number of dependencies for our Portlet project increases and we need to maintain a version based configuration
- We need to use or integrate our Portlet application with an existing Maven based application from an Organizational build repository
In this article we will look at how we can use Maven dependency management in Plugins SDK by still using the default Ant based Liferay SDK build, you can use any of your existing Liferay Plugins SDK project which has external dependencies.
Technical PlatformI have tested this application on the following technical platform, this works irrespective of Operating System.
Software Version Download Link Liferay CE Portal Server (Tomcat) 6.0.x http://sourceforge.net/projects/lportal/files/Liferay%20Portal/6.0.6/liferay-portal-tomcat-6.0.6-20110225.zip/download Liferay CE Plugins SDK 6.0.x http://sourceforge.net/projects/lportal/files/Liferay%20Portal/6.0.6/liferay-plugins-sdk-6.0.6-20110225.zip/download Apache Ant 1.7.x or above, preferred 1.8.x http://ant.apache.org/bindownload.cgi Apache Maven 2.2.1 or above, preferred 3.0.3 http://maven.apache.org/download.html Apache Maven Ant Tasks 2.2.1 or above http://maven.apache.org/ant-tasks/download.html The Server distribution is not required for the subject of the article it’s preferred to have as the Liferay Plugins SDK might/will use some dependencies from the server distribution Setup and InstallationAssuming that you have downloaded and installed the above mentioned softwares, for the sake of convenience we will use the following variable names for respective installation DIR’s,
- $LIFERAY_HOME - the home directory where Liferay server is installed e.g. C:\lportal-6.0.6
- $LIFERAY_SDK_HOME - the home directory where Liferay server is installed e.g. C:\liferay-plugins-sdk-6.0.6
- $ANT_HOME - the home directory where ANT is installed e.g. C:\apache-ant-1.8.2
- $M3_HOME - the home directory where Maven 2.2.x is installed e.g. C:\apache-maven-3.03
Now copy the maven-ant-tasks-2.1.3.jar to $ANT_HOME/lib
Implementation
Let’s use the Liferay IDE to create a new Portlet plug-in look at Using Liferay Maven SDK or you can import the attached Liferay Google Maps demo project in to your workspace,
Open the build.xml of the project that has been created, by default the project build template looks like
Now to Mavenize the default ANT build.xml we do the following,
- Add the xmlns:artifact=” antlib:org.apache.maven.artifact.ant” to the element of the orginal build.xml
- Create a new ant target called “copy-dependencies”, this step is crucial, you can have any name for the target but then what the target does is important. This target will download (only time only) and copy the dependencies to docroot/WEB-INF/lib folder
- Add an ant call to “deploy” target within the “copy-dependencies”, this will enable the build.xml to follow the default Portlet application building and deploying post copying the dependencies
- Make the copy dependencies as the default target for the project
A example of build.xml with above configurations is available here
Observe the artifact:dependencies task portions those are important pieces of mavenizing our ant build. We add the dependencies to the project the same way we add them in Maven pom.xml with little bit of variation to the syntax.
After this once you execute the build in Portlets plug-in directory, it will first download the dependency jars if it does not exist in to the local Maven repository and they will added to the docroot/WEB-INF/lib directory when copy-dependencies target is called, which also includes call to the Liferay default deploy target
Voila! Now we are able to use the Maven dependency management with Liferay Plugins SDK default Ant build system. I hope this article has helped you, for further reading you can check the following links,
Kamesh Sampath 2013-05-14T04:27:21ZHOW-TO Clear Liferay Cache
I was learning on how to implement the export and import functionality on Liferay, initially I thought it to be rather a tedious job but thanks to Liferay API/Framework which made my job easier with Liferay Portlet Data Handlers thanks to Jorge Ferrer who gave me an insight to the API/Framework and how to use the same. All I was required to do is just create a class that extends from BasePortletDataHandler and have it configured via the liferay-portlet.xml
But this activity lead to an interesting learning, initially when I implemented this I saw that data was getting exported/imported without any errors but then I see that its not refreshing the UI immediately after the import. This kind of annoyed me for long time .. thanks to Raymond Auge for is timely insight that we need to clear the cache for the same to be refreshed.. so started my next task on hunting the class which can do the job..
The initial analysis started with me doing the manual task of clearing the caches via the Portal Control Panel using the Server Administration --> Resources (tab) --> Actions panel where we have the action buttons that will clear the cache held by Database, Virtual Machine both local and clustered... when i did this sequence of actions after my Import, i see the data getting refreshed instantly.. so whats next ? finding out the class that did these jobs, when back tracing from the Server Admin page i landed up in the class EditServerAction, there I got the following three sweet little methods that can do the job for me,
- CacheRegistryUtil.clear() - to clear all the Database caches
- MultiVMPoolUtil.clear() - clearing cache across JVM clusters
- WebCachePoolUtil.clear() - clearing cache in Single VM
All left with me post this findings is that i need to call the required or all methods post my successful import of the data to clear the required caches...
Kamesh Sampath 2013-05-14T04:26:13ZUsing liferay-ui:search-toggle - with Basic or Advanced Search only
I was using <liferay-ui:search-toggle> tag, and my requirement was to to show only advanced search and no basic search. but by default <liferay-ui:search-toggle> will show basic search unless and until user clicks the advanced search atleast once. I tried all possible ways and finally found the solution, this what i did to make my <liferay-ui:search-toggle>show only "Advanced Search" without "Basic" search toggle link.So what we need to do is,
- We need to override the isAdvancedSearch method of the XDisplayTerms class to always return true, where "X" your class prefix e.g.ArticleDisplayTerms which extends form com.liferay.portal.kernel.dao.search.DisplayTerms
- Update your *_search.jsp which has the <liferay-ui:search-toggle> with the following piece of code
This style overriding will prevent the "<<Basic" search link form being displayed, the next piece of code snippet will make the "Advanced" search displayed by default, we are a kind of triggering the Search link click
....
String key = "<replace with the id of your <liferay-ui:search-toggle> tag";
SessionClicks.put(request, key,"advanced");
.....
The key piece of code which does sends signal to the underlying liferay code to show only "advanced" is SessionClicks.put(request, key,"advanced");
The same could be achieved when we want to display only basic search and no advanced search just by changing the "advanced" --> "basic"
That is it, once we have done with this our <liferay-ui:search-toggle> will always display only "Advanced" or "Basic" search
Kamesh Sampath 2013-05-14T04:12:43ZLiferay Portal 6.1-CE on JBoss AS71
After setting up Liferay Portal 6.1-CE on JBoss AS7 based in this post, i thought it was a piece of cake to deploy Liferay Portal 6.1-CE on JBoss AS7.1(Thunder) but not until i found that we need to do few more updates rather changes to Liferay 6.1-JBoss CE bundle.
Here is the list of what we need to do,
$JBOSS_70_HOME - refers to the Liferay 6.1-CE JBoss AS 7.0.2 directory or any JBoss AS 7.0.2 directory where you have deployed Liferay Portal
- Liferay Modules -- Check the $JBOSS_70_HOME/modules/com/liferay/portal/main/module.xml you will see urn:jboss:module:1.0,the we need to update to urn:jboss:module:1.1, once one we can copy it to the $JBOSS71_HOME/modules directory
- You need to repeat this for any additonal modules that you might have deployed to the JBOSSAS_70 JBoss Portal bundle
- Deployment Structure (optional) -- Based on this AS71 post, I understood that JBoss AS71 does not export the system module, but if we check $JBOSS71_HOME/standalone/deployments/ROOT.war/WEB-INF/jboss-deployment-structure.xml you will see an dependency as follows,
How-To implement Pagination in Liferay
Liferay provides a rich set of tag libraries that can help in implementing certain complex functionalities like search container, pagination etc., with few lines of code. In this blog let’s see how we can implement the same. For the demo purposed I used the following technical platform,
- Liferay Portal v6.1.CE (beta)
- Liferay Portal SDK v6.1.CE
- Apache Ant 1.8.2
- RHEL 6.1 (Windows could also be used)
- Eclipse IDE 3.7.1 with Liferay IDE
- The first and fore most step is to define the pagination container, the liferay-ui 1tag provides a the search-container1 tag which could be used to initialize the container
- The next step is to manipulate the result and set the same in pageContext of the JSP page, this is done using the liferay-ui’s search-container-results1, when manipulating the result we need to set the following pageContext variables to enable the Liferay-ui tag to process and display them,
- The third step of the implementation is to define the result row which is done using the liferay-ui’s search-container-row tag, this tag takes the following parameters,
- The fourth step of the implementation is to define the columns that will be displayed in the resulting table, this is done using the liferay-ui’s search-container-column-text[1] this tag takes the following two properties,
- The last and final step of the implementation is to define the paginator element of the results which will help in navigating across pages typically First, Next, Previous, Last etc., this is done using the liferay-ui’s search-container-row[1]
Using Liferay Portal 6.1 Published in Print
I am pleased to announce the immediate availability of the print edition of Using Liferay Portal 6.1! For those of you on your toes (and you know who you are), it's actually been available since Friday, but who reads a blog entry that is published on Friday afternoon?
It's a big book. We're getting close to 700 pages now in print, and that does not include the properties reference, which we think is better as an online reference than stuffed into the book (plus, we can lower the price if we excise those pages). I want to acknowledge the hard work of Liferay's Knowledge Management team for a job well done: Jim Hinkey, Stephen Kostas, Jesse Rao, and Cody Hoag. In addition to these guys, some other key contributors include James Falkner, Bruno Farache, Michael Han, Jeffrey Handa, Mark Healy, and Jonathon Omahen.
So if you like big, thick books on your shelf, especially ones with the Liferay logo on them, why not pick one up?
Of course, we're not stopping there. I'm in the midst of working on the styling of the epub version of the book, which we'll release next. Stay tuned!
Richard Sezov 2013-05-13T20:42:55ZRE:5 tips to improve usage of the Liferay script console
// In reply to 5 tips to improve usage of the Liferay script console - by Sébastien Le Marchand
Sébastien wrote a very good article about Liferay script console. Here is one more tip in response of the call for sharing at the end of the article. I post it as a sepreate blog entry because I cannot use Gist or format in comment area....
Tip #6: Schedule your script to run as a CRON job If you want to schedule your script to execute at certain times as a CRON job (One scenario can be: Run the task "deactivate users never logged and created since more than 2 years" every month.), you can use Liferay's Scheduler Engine API, like in the following example: The following code outputs the string "test" to a file one time per minute in the next 10 minutes: You can change your job schedule by changing the parameters in CronText constructor. You will also need to use proper escape characters in the script. Note that when Liferay Scheduler Engine execute the script, the following predefined variables are not available:- out (java.io.PrintWriter)
- actionRequest (javax.portlet.ActionRequest)
- actionResponse (javax.portlet.ActionResponse)
- portletConfig (javax.portlet.PortletConfig)
- portletContext (javax.portlet.PortletContext)
- preferences (javax.portlet.PortletPreferences)
- userInfo (java.util.Map<String, String>)
Kan Zhang 2013-05-13T18:26:01Z
Closing the Loop with KnowledgeTree for Salesforce and KnowledgeTree for Mobile
Last month we released KnowledgeTree for Salesforce, the first release of many geared toward empowering enterprise sales organizations to curate and surface just the right content at just the right time. This month, we're excited to share with you some improvements we've made to KnowledgeTree for Salesforce and introduce our brand new KnowledgeTree for Mobile application for iOS. Both help close the loop between marketing teams curating content for the field, and sales teams taking advantage of content in the field. Let's find out how.
KnowledgeTree for SalesforcePublishing content for use in the field should never be a fire-and-forget process. The best content portfolio is pruned and refreshed as needed. But, how can you determine what content needs pruning and why? Your sales team, the ones using the content, can be a great source of feedback about what's working and what isn't.
Imagine a sales rep working diligently in Salesforce. He's got a good opportunity, International Mining, on the hook. Because KnowledgeTree for Salesforce is installed he has instant access to collateral that his marketing team has curated for opportunities such as this.
5 astuces pour améliorer l’usage de la console de script de Liferay
// The english version of this article can be found here: 5 tips to improve usage of the Liferay script console.
// Si vous utilisez un lecteur RSS pour lire ce billet, veuillez basculer vers la page HTML pour voir correctement les morceaux de code.
Depuis la version 6.0, Liferay propose une console de script intégrée dans le Control Panel. Très puissant, cet outil devient vite indispensable dès que l’on y a goûté (si vous ne connaissez pas encore la console de script, jetez un oeil sur l’article d’introduction de Jeffrey Handa).
Dans la suite de ce billet, je vais vous présenter 5 astuces simples pour encore mieux profiter de la console de script.
Les exemples de mise en oeuvre qui suivent sont basés sur le langage Groovy, mais la plupart de ces astuces sont applicables avec les autres langages supportés par la console de script du portail. Astuce n°1 : Mettez du HTML dans vos sorties Il faut savoir que la sortie par défaut de la console de script est rendue directement en tant que contenu HTML. Pensez-donc à intégrer des balises HTML dans vos sorties pour bénéficier d’une mise en forme riche. Exemple de script : Résultat : Astuce n°2 : Affichez les exceptions dans l’interface utilisateur Lorsque une exception survient lors de l'exécution d’un script, le message d’erreur est toujours le même quelque soit l’exception et ne donne aucun détail, ce qui oblige à consulter les logs du serveur pour effectuer un diagnostique. Pour obtenir le détail de l’exception directement dans l’interface utilisateur, encadrez l’ensemble de votre traitement par un bloc try/catch et affichez la stack trace de l’exception sur la sortie de la console (depuis la clause catch).. Example de script : Résultat : A noter que cela ne fonctionne pas pour les erreurs liées à la syntaxe du script. Astuce n°3 : Exploitez les variables prédéfinies Un script exécuté depuis la console du control panel dispose des variables prédéfinies suivantes :- out (java.io.PrintWriter)
- actionRequest (javax.portlet.ActionRequest)
- actionResponse (javax.portlet.ActionResponse)
- portletConfig (javax.portlet.PortletConfig)
- portletContext (javax.portlet.PortletContext)
- preferences (javax.portlet.PortletPreferences)
- userInfo (java.util.Map<String, String>)
Astuce n°5 : Prévoyez une sortie fichier pour les scripts "longue durée" Lorsque l’exécution d’un script dépasse une certaine durée, la console ne répond plus et retourne une erreur, alors même que le script peut continuer son exécution et potentiellement mener à bien l’ensemble de son traitement... Mais impossible de connaître le statut du traitement sans la sortie correspondante ! Pour remédier à cela, il suffit de prévoir une sortie fichier en plus de la sortie console, comme sur l’exemple ci-dessous : Une fois le script initial exécuté, il est possible de lire le fichier généré sans pour autant avoir d’accès direct au système de fichier, en utilisant un second script : A noter que cette technique basée sur un fichier de sortie dédié est préférable à l’utilisation d’un logger classique car elle facilite la récupération des données de sortie du script (qui seraient plus difficile à isoler parmi l’ensemble des logs du portail). Et vous, avez-vous des astuces à propos de la console de script à partager avec la communauté ? Faites en part dans les commentaires de ce billet ! Lectures complémentaires Sébastien Le Marchand 2013-05-13T01:30:15Z
5 tips to improve usage of the Liferay script console
// La version française de cet article est là : 5 astuces pour améliorer l’usage de la console de script de Liferay.
// If you use a RSS reader to read this post, please switch to the HTML page to correctly view the code snippets.
Since the release 6.0, Liferay provide a script console integrated into the Control Panel. Very powerful, this tool becomes fast essential for any portal administrator or developer (if you do not still know the script console, have a look on this article by Jeffrey Handa).
During this post, I am going to present you 5 simple tips to take better advantage of the script console.
The following implementation samples are based on the Groovy language, but most of them are applicable with other languages supported by the portal script console. Tip #1: Use the HTML in your outputs You need to know that the script console default output is rendered as HTML content. Thus, think to embed HTML markup in your outputs to enjoy rich formatting. Script example: Output: Tip #2: Show up exceptions on user interface When any exception arises during script execution, the error message is always the same and give no detail about the error. So, you need to access server logs to make a diagnostic. To show up exception details on the user interface, envelop your whole code with a try/catch block and print the stack trace on the console output (from the catch clause). There is nevertheless a limitation: it doesn’t work for script syntax errors. Script example: Output: Tip #3: Exploit the predefined variables A script executed from the Control Panel can access the following predefined variables :- out (java.io.PrintWriter)
- actionRequest (javax.portlet.ActionRequest)
- actionResponse (javax.portlet.ActionResponse)
- portletConfig (javax.portlet.PortletConfig)
- portletContext (javax.portlet.PortletContext)
- preferences (javax.portlet.PortletPreferences)
- userInfo (java.util.Map<String, String>)
Tip #5: Plan a file output for "long-running" scripts When the execution of a script exceeds a certain duration, the console doesn’t respond any more and returns an error, whereas the script can continue its execution and potentially bring to a successful conclusion... But impossible to know the status without the corresponding output! To by-pass this limitation, you can set up a file output besides the console output, like in the following example: Once the initial script was executed, it is possible to read the generated file without direct access to the file system, by using a second script: Note that method based on a dedicated output file is better than using a classic logger because it’s easier to get back the script output data (which would be more difficult to isolate among all portal logs). And you, do you have some tips about script console that you can share with the community ? Let us know in the comments ! Further reading: Sébastien Le Marchand 2013-05-11T23:35:42Z
Using custom java classes in a JSP hook
In Liferay hook development, one common question is:
How to import/use/access custom java classes in a JSP hook?
The question can be described as:
1. Create a hook project (for example: sample-hook)
2. Create a custom class (for example: com.kzhang.CustomJavaClass) in hook project.
3. Override a Liferay portlet jsp (for example, html/portlet/blogs/view.jsp) and try to use the CustomJavaClass in the jsp. Liferay will throw "class CustomJavaClass can't be resolved to a type" exception or ClassNotFound exception.
Cause
The jsps in hook plugin is deployed to ROOT servlet context. for example, the html/portlet/blogs/view.jsp in hook plugin will be copied to ${container.deploy.folder}/ROOT/html/portlet/blogs/view.jsp, and the origional view.jsp will be renamed as view.portal.jsp.
The custom classes are still remains in the hook servlet context. for example, the com.kzhang.CustomJavaClass in hook plugin will be still in ${container.deploy.folder}/sample-hook/WEB-INF/classes/com/kzhang/CustomJavaClass.class.
In html/portlet/blogs/view.jsp it can not find CustomJavaClass because each servlet context can only see it's own classes and those of the parent classloaders. In our case, the html/portlet/blogs/view.jsp is in ROOT servlet context which can not see the CustomJavaClass in sample-hook servlet context
Solution
There are some discussions in Liferay forum:
http://www.liferay.com/community/forums/-/message_boards/message/7454307
http://www.liferay.com/community/forums/-/message_boards/message/13467179
http://www.liferay.com/community/forums/-/message_boards/message/21397246
http://www.liferay.com/community/forums/-/message_boards/message/11508053
The most common solution is to use the ext plugin instead of hook plugin.
But can we avoid using the ext plugin and leave everything as a hook?Solution 1: Use Spring + PortletBeanLocatorUtil + JAVA reflection
Step 1. Create the custom-spring.xml in /sample-hook/docroot/WEB-INF/src/context/custom-spring.xml folder.
Step 2. In custom-spring.xml, define the bean for your custom java class:
Step 3. In web.xml, add the context-param to load the custom-spring.xml:
Step 4. In custom_jsps/html/portlet/blogs/view.jsp, use PortletBeanLocatorUtil to load the custom java class:
If your CustomJavaClass implements an interface which is accessable in ROOT servlet context, then you can cast the customJavaClass to the interface and use the class thru interface. Otherwise you will need to use JAVA reflection to dynamically invoke the methods in the custom class.
Solution 2: Override Struts Action and call the custom classes in Struts Action.
Setp 1. In liferay-hook.xml, override the view action of blogs portlet:
Step 2. Create the CustomStrutsAction, invoke the custom class in CustomStrutsAction and set the result in to renderRequest attribute:
( Instead of result, you can also set the custom class in the renderRequest attribute and invoke it in jsp either by using it's Interface or use java reflection)
Step 3. In custom_jsps/html/portlet/blogs/view.jsp, get the result from the renderRequest attribute:
Kan Zhang 2013-05-10T20:15:39ZSharePoint Users at a Crossroads
SharePoint users are at a crossroads. They have put a massive amount of content into SharePoint that isn’t always easily retrieved. They have invested time, resources and money trying to configure SharePoint to solve their content management problems. Users are found questioning if SharePoint is efficiently managing their business-critical content processes.
AIIM has realized the challenges that SharePoint users are facing and recently addressed them at the seminar in Toronto, “SharePoint at a Crossroads.”
Attendees at the event were from a broad range of organizations with varying successes, difficulties and questions about SharePoint. Some are looking for more value from their ECM, including mobile and secure cloud solutions. Some have just deployed SharePoint and are experiencing success in their first stages of implementation. Many attendees were looking for SharePoint partners to solve their problems related to scalability, accessibility to content and flexibility of the platform to create unique business solutions.
Alfresco participated in the event as the only ECM alternative to SharePoint. Many participants were partners with add-on solutions to SharePoint or imaging solutions that integrate with many different ECMs. Alfresco uniquely represented one of the options that SharePoint users face—replacing it with another ECM.
A recent survey of over 500 professionals was conducted that found 80 percent of those using SharePoint thought it fell short of their expectations. Alfresco offers many valuable features in comparison to SharePoint:
- Lower cost and higher ROI
- Faster implementations
- More advanced workflow capabilities
- Scalability and stronger search features
- An open platform that more easily integrates with business-critical tools
While not everyone is looking to migrate to a new ECM, there are tools available to better manage content already in SharePoint. To learn more about managing your SharePoint data in Alfresco, watch our webinar recording.
There are many different options to choose from when considering your current ECM investment and where to invest your resources in the future. Alfresco offers a scalable, flexible and cost efficient solution for managing your content. Is SharePoint providing the same for you?
Liferay Sync Mobile 2.0
We are pleased to announce that Sync Mobile 2.0 has been released!
In addition to having incorporated several bug fixes, this version represents the integration of noteable, new features:- Tablet Support: You can, now, use Sync on your iPads and Android tablets.
- Revamped UI: Allows you to fully take advantage of larger screen sizes while providing for a heightened file-previewing experience.
Here are some screenshots of Sync running on an iPad:
You can install Sync from Google Play and App Store.
Bruno Farache 2013-05-08T22:46:18Z
Liferay, WebSockets, and Node: Good Times!
- Coding event-based, asynchronous web program is fun and exciting! There are many frameworks and technologies to make it easy, both on client and server, and if I can do it, anyone can do it :)
- It's really easy to integrate awesome apps with Liferay, due to its Java heritage, rich APIs and lightweight JSON or RESTful web services.
- Java EE features (like JSR-356, aka WebSockets) and other upcoming technologies in Java EE 7 will lower the Java EE learning curve even further.
Creating A Big Media Site in Liferay
I wanted to prototype a site similar to an online tv and movie streaming service that isn't Netflix. I wanted to find a versital carousel that worked well with responsive (Flexslider2). I wanted the heading to become more of a solid background color after you scrolled down past the main carousel.
The carousels are fluid when the window is resized.
screenwidth: 1280px
screenwidth: 1024px
screenwidth: 480px
(after scroll past the main carousel the banner becomes a transparent color instead of gradient background image)
I loaded the additional js file for the carousel when detected
In the Main Carousel.vm velocity template I tweaked some of the js.
- After the first slide is loaded I remove the loading class on the body tag.
- I detect if there is a banner and toggle the banner from absolute position to fixed if the dockbar was still on the screen.
- Detect the height of the carousel - #banner height then if vertical scroll is larger than that number then I add a class of changed, which replaces the background image with a background color.
Crafter + Alfresco Powers Next Generation Websites
“Web content management is evolving from website publishing to digital experience support,” according to Forrester’s WCM for Digital Customer Experience Q2 2013.
What does Forrester mean? You don’t need an explanation if…
- You’re reading this on a smartphone or tablet
- You’ve updated a website on your own, without sending files to an IT person
- You rely on user generated or suggestions from trusted communities
Websites were once about flat content with little interaction. Today, that sort of nostalgia doesn’t play. What we expect is…
- A digital experience that flows from browser to tablet to mobile flawlessly
- A site to be responsive to our requests with targeted information
- Communities to suggest and bubble up the best ideas, relevant to our needs
Building these abilities into a website isn’t easy. It takes more than pretty pictures and snappy text. It takes extensive use of digital assets integrated into the web experience. It assumes responsive design for viewing on any screen. It requires content targeting for presentation of the right content at the right time. It takes a dedicated tool purpose built for accomplishing the goal of delivering an awesome web experience. Yet many web and content experience management solutions are heavy, hard to learn and expensive.
Alfresco has a solution for WCM that it is built around the open strategy of content services. As a strategy, we decided to be committed to what we do best, manage digital content. And although the core of WCM is managing digital content, today’s modern web requires a comprehensive solution. Welcome Crafter, you do it very well.
Who says?
- YouSendIt: “Crafter enabled our marketing and web development teams to easily deliver dynamic and engaging content, while knowing we have preeminent Crafter experts on hand for support,” said Steve Ceplenski, Senior Director, Web Services at YouSendIt. “Using Crafter’s next generation technology, we are able to quickly develop targeted content for our brand, and easily integrate with a SaaS translation system to manage sites in multiple languages.”
- Full Sail University: “We wanted to make use of rich web media, including flash and video in our new website and Alfresco did not limit us in any way. Combining Crafter with Alfresco allowed us increased flexibility and to scale with relative ease” Mark Gilbert, VP Information and Media Technologies. Read more here.
- MasterCard, National Academy of Sciences and Harvard Business Publishing to name a few – check out more references here.
Today we welcome Crafter Software to the Alfresco Partner Program as their own organization with their own team to sell and support the solution. Check out their website to learn more and read more about the great work they are doing!
Select Category And add Post in message board using velocity template
Hi Guys,
It is possible to put web content of MB-category in every page rather than to display message board in every page in website .
On selecting category, we will open a pop-up dialog box for inserting Post in message board.
Template Code :
#set ($MBLocalService= $serviceLocator.findService("com.liferay.portlet.messageboards.service.MBCategoryLocalService")) #set($cat=$MBLocalService.getCategories($groupId)) <form name="frmmb" id="frmmb"> <select name="foo" id="foo" onchange="pop(this.value)"> <option value= "select"> -select-- </option> #foreach ( $c in $cat) <option value= "$c.getCategoryId()"> $c.getName() </option> #end </select> </form> <script type="text/javascript" charset="utf-8"> function pop(value) { var s=value; alert(s); AUI().ready('aui-dialog','aui-dialog-iframe','liferay-portlet-url', function(A) { var url = Liferay.PortletURL.createRenderURL(); url.setPortletId("19"); url.setWindowState('pop_up'); url.setParameter("&_19_struts_action=%2Fmessage_boards%2Fedit_message&_19_mbCategoryId="); window.myDialog = new A.Dialog( { title: 'Ask a Question?', width: 640, centered: true } ). plug( A.Plugin.DialogIframe, { uri: url.toString()+""+s, iframeCssClass: 'dialog-iframe' } ).render(); }); } </script> <input type="button" class="aui-button-input aui-button-input-submit" name="dialog" value="Select Catagory & Add Question" />
I implemented this code at http://liferay.medicalassociation.in/ask-question Visit For Better Understanding .
chirag @ India 2013-05-07T12:13:42Z