AdoptOS

Assistance with Open Source adoption

ECM

Coming Soon: TripWire

Liferay - Tue, 03/28/2017 - 23:23

For the last few months as I've been working with Liferay 7 CE / Liferay DXP, I've been a little stymied trying to manage the complexities of the new OSGi universe.

In Liferay 6.x, for example, an OOTB demo setup of Liferay comes with like 5 or 6 war files.  And when the portal starts up, they all start up.

But with Liferay 7 CE and Liferay DXP, there are a lot of bundles in the mix. Liferay 7 CE GA3, for example, has almost 2,500 bundles in OSGi.

And when the portal starts up, most of these will also start. Some will not. Some might not be able to. Some can't start because they have unsatisfied dependencies.

But you're not going to know it.

Seriously, you won't know if something has failed to start when you restart your environment. There may or may not be something in the log. Someone might have stopped a bundle intentionally (or unintentionally) in the gogo shell w/o telling you. And with almost 2,500 bundles in there, it's going to be really hard finding the needle in the haystack especially if you don't know if there's a needle in there at all.

So I've been working on a new utility over the past few months to resolve the situation - TripWire.

Features

TripWire actually scans the OSGi environment to gather information about deployed bundle statuses, bundle versions, and service components. Tripwire also scans the system and portal properties too.

This scanning is done at two points, the first is when an administrator takes a snapshot (basically to persist a baseline for all comparisons), and the second is a scheduled task that runs on the node to monitor for changes. The comparison scan can also be kicked off manually.

After installing TripWire and navigating to the TripWire control panel, you'll be prompted to capture an initial baseline scan:

Click the Take Snapshot card to see the system snapshot:

You can save the new baseline (to be compared against in the automated scans), you can export the snapshot (downloads as an excel spreadsheet), or you can cancel.

Each section expands to show captured details:

The funny looking hash keys at the top? Those are calculated hashes from the scanned areas, by comparing the baseline hash against the scanned hash, TripWire knows quickly if there is a variation between the baseline and the current scan.

When you save the new baseline, the main page will reflect that the server is currently consistent with the baseline:

You can test the server to force a scan by clicking on the Test Server card:

Exclusions

TripWire supports dynamically creating exclusion rules to exclude items from being part of the scan.  You might add an exclusion for a property value that you're not interested in monitoring, for example. Click on the Exclusions card and then on the Add New Exclusion Rule button:

The Camera drop down lists all of the current cameras used when taking a snapshot. Choose either a specific camera or the Any Camera option to allow for a match to any camera.

The Type drop down allows you to select either a Match, a Starts With, a Contains or a Regular Expression type for the exclusion rule.

The value field is what to match against, and the Enabled slider allows you to disable a particular exclusion rule.

Modifying the exclusion rules will affect scans immediately resulting in failed scans:

By adding the rule to exclude any System Property that starts with "catalina.", scans now show the server to be inconsistent when compared to the baseline. At this point you can take a new baseline snapshot to approve the change, or you could disable the exclusion rule (basically reverting the change to the system) to restore baseline consistency.

Notifications

TripWire uses Liferay notifications to alert subscribed administrators when the node is in an inconsistent state and when the node returns to a consistent state. For Liferay 7 CE, a subscribed administrator will only receive notifications about the single Liferay node. For Liferay DXP, subscribed administrators will receive notifications from every node that is out of sync with the baseline snapshot.

Notifications will be issued for every failed scan on every node until consistency is restored.

To subscribe or unsubscribe to notifications, click on the Subscriptions card. If you are unsubscribed, the bell image will be grey, if you are subscribed the bell will be blue and have a red notification number on it. Note this number does not represent the number of notifications you might currently have, it is just a visual marker that you are subscribed for notifications.

Configuration

TripWire supports setting configuration for the scanning schedule. Click on the Configuration card:

Using the Cameras tab, you can also choose the cameras to use in the snapshots and scans:

Normally I recommend enabling all but the Separate Service Status Camera (because this camera is quite verbose in the details it captures).

The Bundle Status Camera captures status for each bundle.

The Bundle Version Camera captures versions of every bundle.

The Configuration Admin Camera captures configuration changes from the control panel.  Note that CA only saves values that are different from the set of default values on each panel, so the details on this section will always be shorter than the actual set of configurations saved for the portal.

The Portal Properties Camera captures changes to known Liferay portal properties (unknown properties are ignored). In a Liferay DXP cluster, some properties will need to be excluded using the Exclusion Rules since nodes will have separate, unique values that will never match a baseline.

The Service Status Camera captures counts of OSGi DS Services and their statuses.

The System Properties Camera captures changes to system properties from the JVM. Like the portal properties, in a Liferay DXP cluster some properties will need to be excluded using Exclusion Rules since nodes will have separate, unique values that will never match a baseline.

The Unsatisfied References Camera captures the list of bundles with unsatisfied references (preventing the bundles from starting). Any time a bundle has an unsatisfied reference, the bundle and it's unsatisfied reference(s) will be captured by this camera.

The three email tabs configure who the notification emails are from and the consistent/inconsistent email templates.

Liferay DXP

For Liferay DXP clusters, TripWire uses the same baseline across all nodes in the cluster and reports on cluster node inconsistencies:

Clicking on the server link in the status area, you can review the server's report to see where the problems are:

Some of the additions and changes are due to unique node values and should be handled by adding new Exclusion Rules.

The Removals above show that one node in the cluster has Audience Targeting deployed but the other node does not. These are the kinds of inconsistencies that you may not be aware of from a cluster perspective but would result in your DXP cluster not serving the right content to all users, and identifying this discrepancy once in your cluster in an easy and quick way will save you time, money and effort.

For your cluster Exclusion Rules, your rule list will be quite long:

Conclusion

That's TripWire.

It will be available soon in the Liferay Marketplace for both Liferay 7 CE and Liferay DXP.

There is a cost for each version, but that is to offset the time and effort I have invested in this tool.

And while there may not seem to be an immediate return, the first time this tool saves you by identifying a node that is out of sync or an unauthorized change to your OSGi environment, it will save you time (in waiting for the change to be identified), effort (in having to sort through all of the gogo output and other details), user impressions (from cluster node sync issues) and most of all, money.

TripWire is currently under review for Marketplace release, and I'll post an update once it is available.

 

David H Nebinger 2017-03-29T04:23:11Z
Categories: CMS, ECM

Mobile First with Liferay Screens – part 4 Webinar: Mobile Strategy: Optimizing for the Connected Customer

Liferay - Wed, 03/22/2017 - 05:27

 

Mobile First with Liferay Screens – part 4
Webinar:
Mobile Strategy: Optimizing for the Connected Customer

 

Mobile apps have become an integral part of our communication with customers and personnel. After all, the best way of reaching people is on the devices they use the most: the smartphone and the tablet. With Liferay Screens, a mobile app is also part of a sophisticated digital experience platform. It helps us to 'listen' to our users better and then be of service to them with the right information and functionality. On 4 April, José Manuel Navarro and I will be giving a webinar about Liferay Screens. You can register now!

 

Liferay Digital Experience Platform

With the launch of DXP in 2016, Liferay set course in a new direction. A direction in which organizations communicate more intensively with their target group in order to build effectively on lasting relationships. Major steps were taken in the field of Audience Targeting, which I see as genuine progress. The addition of elements from Social Office is another improvement, in my view. Features that we had to install individually in the past are now integrated into the product. This means there is much more available in the way of social and collaboration elements – absolutely out-of-the-box.

With DXP, features and functionality developed or improved by Liferay should be easier to incorporate than in the past. In theory, customers would be increasingly in the driver’s seat and can decide themselves to what extent they will actually use the components offered by Liferay. Whether this works well in practice and whether it is really so simple are things we still have to find out.

 

Personalized customer journey

For the Liferay developer, life has perhaps not immediately become simpler or clearer with the advent of DXP. But for the user, the experience has already improved considerably. The way you view a list, how buttons work and what they look like, the way forms work – these experiences have been extrapolated much further in everything a normal user sees on the screen. If they expect the same, then they get the same.

In this way, Liferay’s new course leads to a uniform digital world that users can increasingly shape to their own wishes. Thanks to Liferay Screens, they can also continue their personalized customer journey effortlessly on their smartphones and tablets. A digital experience platform in your pocket!

 

Liferay Screens rapid development tool

Liferay Screens makes it possible for native apps to make use of the content and web services of the Liferay Digital Experience Platform. The tool works with screenlets, reusable components which can be compared with the familiar Liferay plug-ins. Componence has extensive experience with the development of native mobile apps on the basis of Liferay Screens. We have an extremely thorough knowledge of this tool, and can adapt and expand the standard Liferay screenlets for our customers if required.

Besides this, Componence has already been working for some time on a collection of screenlets of its own. Our screenlets library includes familiar Liferay functionalities such as Localization, Menu, Global Search, Web Content List, Web Content Detail, Comments, Subscription, Notifications, Calendar and User Search. In addition, we now have blog and vlog functionality at our disposal. This means we can create a cost-efficient native mobile app within a short period, which completely satisfies all today’s requirements and wishes.

 

Expansion of Componence screenlets

Naturally, Componence will continue to expand and improve its own screenlets library. A modification now on the drawing board for one of our customers – both for the web and for the app – focuses on searching for users. In the future, this component will also provide information about the location where the person concerned works and which team they are in. In addition, Componence will make the Liferay forum with all its corresponding functionality suitable for mobile apps. It goes without saying that it will still be possible to deal with the management of the forum via the web side.

Users will have the option of deciding for themselves which news categories to follow. They will be able to alter these settings themselves. In the Marketplace, supply and demand can be shared – 'I have tickets for the cinema tonight' or 'I am looking for a free workspace'. Frequently-asked questions will be answered from the knowledge base, which we are constantly expanding with new question-and-answer components, including searching.

 

Webinar Mobile Strategy: Optimizing for the Connected Customer

The future of our mobile apps is characterized by the ongoing personalization of the digital world and the optimum use of the possibilities of our mobile devices. For example, iBeacons and other IoT solutions. Your users, too, now expect a uniform customer journey – from their PC to their smartphone and tablet, and vice versa. Many will already not be satisfied with less.

In the webinar Mobile Strategy: Optimizing for the Connected Customer, I will demonstrate how we use Liferay Screens to create this uniform customer journey. What are the advantages of a native mobile app based on this tool? And what can we achieve with the various libraries that are available at this time? I will illustrate this with a demo of the Componence app.

José Manuel Navarro, lead mobile software engineer at Liferay, will tell you more about the technical aspects of the Liferay Screens development tool. What are the advantages of native compared with hybrid, for example? You will find out on 4 April.

 

Register now!

Are you interested in a native mobile app in combination with Liferay? And would you like to know more about the possibilities of Liferay Screens? Then register today for the webinar Mobile Strategy: Optimizing for the Connected Customer on 4 April, 16.00 - 17.00 CET. No technical knowledge is required for this webinar, which will be given in English. Participation is free.

Do you have any questions about the webinar or about Liferay Screens? Then please feel free to contact me on mvanheiningen@componence.nl. You can also register directly, of course. Go to Mobile Strategy: Optimizing for the Connected Customer.

Maarten van Heiningen 2017-03-22T10:27:42Z
Categories: CMS, ECM

Liferay DXP and WebLogic...

Liferay - Tue, 03/21/2017 - 12:56

For those of you deploying Liferay DXP to WebLogic, you will need to add an override property to your portal-ext.properties file to allow the WebLogic JAXB implementation to peer inside the OSGi environment to create proxy instances.

I know, it's a mouthful, but it's all pretty darn technical. You'll know if you need this if you start seeing exceptions like:

java.lang.NoClassDefFoundError: org/eclipse/persistence/internal/jaxb/WrappedValue at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at java.lang.ClassLoader.defineClass(ClassLoader.java:642) at org.eclipse.persistence.internal.jaxb.JaxbClassLoader.generateClass(JaxbClassLoader.java:124) at org.eclipse.persistence.jaxb.compiler.MappingsGenerator.generateWrapperClass(MappingsGenerator.java:3302) Truncated. see log file for complete stacktrace Caused By: java.lang.ClassNotFoundException: org.eclipse.persistence.internal.jaxb.WrappedValue cannot be found by com.example.bundle_1.0.0 at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:444) at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:357) at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:349) at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:160) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) Truncated. see log file for complete stacktrace

Suffice it to say that you need to override the module.framework.properties.org.osgi.framework.bootdelegation property to add the following two lines:

org.eclipse.persistence.internal.jaxb,\ org.eclipse.persistence.internal.jaxb.*,\

You have to include all of the packages from the value defined in portal.properties, so my entry actually looks like:

module.framework.properties.org.osgi.framework.bootdelegation=\ __redirected,\ com.liferay.aspectj,\ com.liferay.aspectj.*,\ com.liferay.portal.servlet.delegate,\ com.liferay.portal.servlet.delegate*,\ com.sun.ccpp,\ com.sun.ccpp.*,\ com.sun.crypto.*,\ com.sun.image.*,\ com.sun.jmx.*,\ com.sun.jna,\ com.sun.jndi.*,\ com.sun.mail.*,\ com.sun.management.*,\ com.sun.media.*,\ com.sun.msv.*,\ com.sun.org.*,\ com.sun.syndication,\ com.sun.tools.*,\ com.sun.xml.*,\ com.yourkit.*,\ org.eclipse.persistence.internal.jaxb,\ org.eclipse.persistence.internal.jaxb.*,\ sun.*

Enjoy

David H Nebinger 2017-03-21T17:56:20Z
Categories: CMS, ECM

Smart Content EE is now available for Liferay 6.2!

Liferay - Tue, 03/14/2017 - 07:51

A few weeks ago we introduced you our new portlet for Liferay 6.2 CE and now we’re happy to announce Smart Content for Liferay 6.2 EE as well with continuous product support and future version updates.

 

Our portlet has many new features and properties that let you display your content in a smart, creative and flexible way.  To try out, please download our 30 days trial version from the Smart Content EE product page!

We would be really happy to read about your opinion and remarks, please share them with us anytime!

Smart Content is available for Liferay 6.2 CE as well and for Liferay 6.1 we recommend you the Webtown Web Content Display portlet for free on Marketplace.

Orsolya Kuti 2017-03-14T12:51:45Z
Categories: CMS, ECM

Adding Portlet URL in the Portlet Toolbar in Liferay 7

Liferay - Tue, 03/07/2017 - 08:12

Portlet URL can be added using Portlet Tool Bar Contributor module. Here also osgi plays its magic of modularity. It can be implemented through OSGI service component. Service component can be either in same module or different one. Wiki page elaborate it through blade tool. Below are steps to implement it  through eclipse IDE. 

 

Create Module Project and select Template as shown below.

 

It will auto generate Portlet Tool Bar Component class. In the component class one thing is necessary the portlet id on which you want to add toolbar.Now Override the method as shown below to add URL in Menu Item that will be redirected once user click the URL.

 

 

Deploy the module, you can see the Icon defined above on the portlet Header.

Multiple URL Menu Item Can be added following the same approach. Permission check can be done by getting the reference of permission checker in the service component.  Permission check will ensure whether to show URL to a User based on granted permissions.

Sushil Patidar 2017-03-07T13:12:14Z
Categories: CMS, ECM

SourceForge Project of the Month

Liferay - Mon, 03/06/2017 - 15:58
Introduction

Liferay Portal has been nominated for the SourceForge Project of the Month for April! Nominees are selected from projects that have recently been a Project of the Week, have a high total number of downloads in the previous month, are generally well-established and have positive user feedback. Should Liferay be elected as the Project of the Month, we will be featured on the SourceForge homepage for the entire month of April and be featured in an interview on their blog. Being featured is a great way to publicize our project by reaching out to SourceForge’s 3 million registered users.

Voting

Liferay Portal is listed among many other great open source projects. To vote you must have a SourceForge account and go to this forum post: https://sourceforge.net/p/potm/discussion/vote/thread/3ad837b8/. Show your support by adding a comment on the thread with: VOTE: lportal

Voting is now open now until March 15th. Thank you for your support!

Jamie Sammons 2017-03-06T20:58:15Z
Categories: CMS, ECM

Using Feature-As-A-Service (FaaS) Is A Faster, Smarter Way To Develop Your Next App

Liferay - Wed, 03/01/2017 - 13:35

Today, it seems as if there’s an app for every aspect of life. From catching pokemon to learning to cook, apps have redefined how brands can connect with consumers, and given budding developers a way to launch their own creations to the market.

 

In 2017, total app revenue is estimated to reach $76.52bn, and paid apps are expected to see almost $2bn in growth. As apps continue to generate such immense revenue and play a variety of key roles in consumers’ lives, competition on the market will remain incredibly fierce. To secure a place on people’s devices, developers have to produce high-quality apps in a cost-effective, time-efficient way.

 

This is where FaaS comes in.

 

How can FaaS Help Developers Improve Their Work?

 

The process of building software has evolved considerably in the past few decades. From the days of developers wrestling with complex machine code, to programming languages and, eventually, to SWIFT, creating applications has gradually become more streamlined.

 

Open-source technology has allowed developers to share codes and reuse elements again and again, while the cloud’s growth has enabled them to outsource various key backend functions (such as payment processing) to save time.

 

Feature-as-a-Service (FaaS) takes this further, providing developers with off-the-shelf features for their app’s front end. They now have the freedom to integrate specific functions and tools into their app without having to build it from scratch, leaving them free to focus on the overall package rather than investing time into orchestrating each and every function.

 

No Need to Reinvent the Wheel

 

By using pre-made FaaS features, everything from social-media functionality and navigation can be included in an app.

 

As the basic infrastructure of apps today is largely the same, there’s no need for developers to build their own versions of them to effectively create a carbon-copy. Think of it as building a house: you can go to a retailer and order everything you need, but can still put it together yourself for a unique result.

 

Likewise, a unique app can evolve from widely-used underlying elements. By providing a slight innovative tweak or combining certain features, developers are able to enhance what’s already there instead of having to reinvent it altogether.

 

Reach the Market Faster than Ever

 

Using FaaS enables developers to bring apps from the conceptual stage to market much faster than before. Developers can free up their production schedules with FaaS and focus on their key value proposition instead, rather than trying to formulate solutions for problems that have already been fixed.

 

Time is of less importance for solo developers creating apps as a hobby or side-business, but for companies dedicated to producing multiple apps a week or month, boosting productivity offers the potential to boost revenue too.

 

Another benefit of using FaaS in your app? It increases the overall quality, as you’re drawing on the skills of a business which specializes in this specific feature. Rather than you having to juggle developing this as well as countless other features, the off-the-shelf element you use instead is its creators’ primary focus.

 

This tends to result in app architecture and design of a far higher standard than anything created by developers struggling to piece an entire app together from scratch. This has a trickle-down effect, with every step of the process improving the consumer's’ experience: from the FaaS provider, to the app-development team, to the user.

 

If you need to integrate voice and video chat into your app, for example, you can add Agora.io’s interactive broadcasting SDK performance service for high-end performance . Both commercial and domestic users depend on real-time-communication platforms to connect with people across the globe, and standard WebRTC is susceptible to common network issues, such as lagging, loss of signal, and dips in quality.

 

If you’re creating an app which aims to enhance business-users’ productivity, a sub-standard RTC feature may not provide enough high-quality performance to stand out. A cutting-edge solution, on the other hand, has the power to improve your long-distance connections and ensure better communication all-round.

 

This is a complex area, but by simply investing in an FaaS like this, developers can make the integration process much simpler for themselves – and improve the user's’ QoE (quality of experience).

 

So: faster production-cycles, a greater focus on creating unique apps, and a greater quality of experience for consumers. Have you considered just how FaaS could revolutionize your development process?

Charlie Day 2017-03-01T18:35:56Z
Categories: CMS, ECM

Creating a Spring MVC Portlet War in the Liferay Workspace

Liferay - Tue, 02/28/2017 - 23:44
Introduction

So I've been working on some new Blade sample projects, and one of those is the Spring MVC portlet example.

As pointed to in the Liferay documentation for Spring MVC portlets, these guys need to be built as war files, and the Liferay Workspace will actually help you get this work done. I'm going to share things that I learned while creating the sample which has not yet been merged, but hopefully will be soon.

Creating The Project

So your war projects need to go in the wars folder inside of your Liferay Workspace folder, basically at the same level as your modules directory. If you don't have a wars folder, go ahead and create one.

Next we're going to have to manually create the portlet project. Currently Blade does not have support for building a Spring MVC portlet war project; perhaps this is something that can change in the future.

Inside of the wars folder, you create a folder for each portlet WAR project that you are building. To be consistent, my project folder was named blade.springmvc.web, but your project folder can be named according to your standards.

Inside your project folder, you need to set up the folder structure for a Spring MVC project. Your project structure will resemble:

For the most part this structure is similar to what you would use in a Maven implementation. For those coming from a legacy SDK, the contents of the docroot folder go to the src/main/webapp folder, but the docroot/WEB-INF/src go in the src/main/java folder (or src/main/resources for non-java files).

Otherwise this structure is going to be extremely similar to legacy Spring MVC portlet wars, all of the old locations basically still apply.

Build.gradle Contents

The fun part for us is the build.gradle file. This file controls how Gradle is going to build your project into a war suitable for distribution.

Here's the contents of the build.gradle file for my blade sample:

buildscript { repositories { mavenLocal() maven { url "https://cdn.lfrs.sl/repository.liferay.com/nexus/content/groups/public" } } dependencies { classpath group: "com.liferay", name: "com.liferay.gradle.plugins.css.builder", version: "latest.release" classpath group: "com.liferay", name: "com.liferay.css.builder", version: "latest.release" } } apply plugin: "com.liferay.css.builder" war { dependsOn buildCSS exclude('**/*.scss') filesMatching("**/.sass-cache/") { it.path = it.path.replace(".sass-cache/", "") } includeEmptyDirs = false } dependencies { compileOnly project(':modules:blade.servicebuilder.api') compileOnly 'com.liferay.portal:com.liferay.portal.kernel:2.6.0' compileOnly 'javax.portlet:portlet-api:2.0' compileOnly 'javax.servlet:javax.servlet-api:3.0.1' compileOnly 'org.osgi:org.osgi.service.component.annotations:1.3.0' compile group: 'aopalliance', name: 'aopalliance', version: '1.0' compile group: 'commons-logging', name: 'commons-logging', version: '1.2' compileOnly group: 'javax.servlet.jsp.jstl', name: 'jstl-api', version: '1.2' compileOnly group: 'org.glassfish.web', name: 'jstl-impl', version: '1.2' compile group: 'org.springframework', name: 'spring-aop', version: '4.1.9.RELEASE' compile group: 'org.springframework', name: 'spring-beans', version: '4.1.9.RELEASE' compile group: 'org.springframework', name: 'spring-context', version: '4.1.9.RELEASE' compile group: 'org.springframework', name: 'spring-core', version: '4.1.9.RELEASE' compile group: 'org.springframework', name: 'spring-expression', version: '4.1.9.RELEASE' compile group: 'org.springframework', name: 'spring-webmvc-portlet', version: '4.1.9.RELEASE' compile group: 'org.springframework', name: 'spring-webmvc', version: '4.1.9.RELEASE' compile group: 'org.springframework', name: 'spring-web', version: '4.1.9.RELEASE' }

So first is the buildScript and the CSS builder apply line followed by war customization stanza.

These parts are currently necessary to support compiling the SCSS files into CSS and store the files in the right place in the WAR. Note that Liferay currently sees this manual execution of the CSS builder plugin as a bug and plan on fixing it sometime soon.

Managing Dependencies

The next part is the dependencies, and this will be the fun part for you as it was for me.

You're going to be picking from two different dependency types, compile and compileOnly. The big difference is whether the dependencies get included in the WEB-INF/lib directory (for compile) or just used for the project compile but not included (compileOnly).

Many of the Liferay or OSGi jars should not be included in your WEB-INF/lib directory such as portal-kernel or the servlet or portlet APIs, but they are needed for compiles so they are marked as compileOnly.

In Liferay 6.x development, we used to be able to use the portal-dependency-jars in liferay-plugin-package.properties to inject libraries into our wars at deployment time. But not for Liferay 7 CE/Liferay DXP development.

The portal-dependency-jars property in liferay-plugin-package.properties is deprecated in Liferay 7 CE/Liferay DXP. All dependencies must be included in the war at build time.

Since we cannot use the portal dependencies in liferay-plugin-package.properties, I had to manually include the Spring jars using the compile type. 

Conclusion

Yep, that's pretty much it.

Since it's in the Liferay Workspace and is Gradle-built, you can use the gradle wrapper script at the root of the project to build everything, including the portlet wars.

Your built war will be in the build/libs directory in project, and this war file is ready to be deployed to Liferay by dropping it in the Liferay deploy folder.

Debugging "ClassNotFound" exceptions, etc, in your war file can be extremely challenging since Liferay doesn't really keep anything around from the WAR->WAB conversion process. If you add the following properties to portal-ext.properties, the WABs generated by Liferay will be saved so you can open the file and see what jars were injected and where the files are all found in the WAB.

module.framework.web.generator.generated.wabs.store=true module.framework.web.generator.generated.wabs.store.dir=${module.framework.base.dir}/wabs

If you want to check out the project, it is currently live in the blade samples: https://github.com/liferay/liferay-blade-samples/tree/master/liferay-workspace/wars/blade.portlet.springmvc.

David H Nebinger 2017-03-01T04:44:37Z
Categories: CMS, ECM

Proper Portlet Name for your Portlet components...

Liferay - Tue, 02/28/2017 - 22:27

Okay, this is probably going to be one of my shortest blog posts, but it's important.

Some releases of Liferay have code to "infer" a portlet name if it is not specified in the component properties.  This actually conflicts with other pieces of code that also try to "infer" what the portlet name is.

The problem is that they sometimes have different requirements; in one case, periods are fine in the name so the full class name is used (in the portlet component), but in other cases periods are not allowed so it uses the class name with the periods replaced by underscores.

Needless to say, this can cause you problems if Liferay is trying to use two different portlet names for the same portlet, one that works and the other that doesn't.

So save yourself some headaches and always assign your portlet name in the properties for the Portlet component, and always use that same value for other components that also need the portlet name.  And avoid periods since they cannot be used in all cases.

So here's an example for the portlet component properties from one of my previous blogs:

@Component( immediate = true, property = { "com.liferay.portlet.display-category=category.system.admin", "com.liferay.portlet.header-portlet-css=/css/main.css", "com.liferay.portlet.instanceable=false", "javax.portlet.name=" + FilesystemAccessPortletKeys.FILESYSTEM_ACCESS, "javax.portlet.display-name=Filesystem Access", "javax.portlet.init-param.template-path=/", "javax.portlet.init-param.view-template=/view.jsp", "javax.portlet.resource-bundle=content.Language", "javax.portlet.security-role-ref=power-user,user" }, service = Portlet.class ) public class FilesystemAccessPortlet extends MVCPortlet {}

Notice how I was explicit with the javax.portlet.name?  That's the one you need, don't let Liferay assume what your portlet name is, be explicit with the value.

And the value that I used in the FilesystemAccessPortletKeys constants:

public static final String FILESYSTEM_ACCESS = "com_liferay_filesystemaccess_portlet_FilesystemAccessPortlet";

No periods, but since I'm using the class name it won't have any collisions w/ other portlet classes...

Note that if you don't like long URLs, you might try shortening the name, but stick with something that avoids collisions, such as first letter of packages w/ class name, something like "clfp_FilesystemAccessPortlet" or something. Remember that collisions are bad things...

And finally, since I've put the name in an external PortletKeys constants file, any other piece of code that expects the portlet name can use the constant value too (i.e. for your config admin interfaces) and you'll know that all code is using the same constant value.

Enjoy!

David H Nebinger 2017-03-01T03:27:57Z
Categories: CMS, ECM

Liferay Hackday 2017

Liferay - Tue, 02/28/2017 - 16:31
  Every other year we have a company retreat where people from all over the world travel to California for a series of meetings and team building activities.   This is a very unique opportunity for us and we're always thinking about ways to maximize it. This time we decided to organize another internal hackathon. That way participants could finally put a face to a GitHub user and have the chance to interact with people they never worked with before in a smaller, fun-setting environment.   The idea of this article is to tell the story of how we made this happen and hopefully help you to organize a similar initiative.     Registration For lots of developers participating on this hackathon is amazing! It's a whole day where you can stop whatever you're doing, get paid to build whatever you want, have free food, and in the end, get some prizes.   But not everybody likes to write code in a fast pace, not everybody likes to compete with others, and not everybody likes to stay in the office until late. You must respect that.   That means our first step was to build a site for people to register and explain how all that would work. You know, rules, expectations, agenda, etc.     Starting At 8:30am participants started to arrive.   We began the day by asking them to write ideas on a piece of paper and come in front of everybody to pitch their proposals. Our only instruction was:   Describe what you wanna do and what are the resources you need to make it happen.   The recruiting process was very organic, but we encouraged them to choose people that didn’t belong to their usual departments and regions. We also wanted to foster open source development, that means every project had to be hosted on GitHub.     Action Once all teams were formed, it was time to start developing the ideas.   Some people are very competitive so they began to work frenetically whereas others were going slowly. You can't really interfere with how people work, but you can definitely influence and stimulate a different kind of environment. That's why we put on very loud music to shake things up and a huge countdown to remind them that time was ticking away.   From time to time, I’d visit teams to check how things were moving.   Acting as a mentor, facilitator, or simply giving an outside perspective is crucial to a team's success.   Food needs to be served throughout the day, however we did it in such a way that was not intrusive and didn’t cause too many distractions.     Awards In our previous Hackday, we decided that we didn't want to have one single winner. We wanted them to feel like they accomplished something and were rewarded by this. That’s why we kept the same four categories as before.   Best Technical Achievement — Did the participants solve a hard technical problem? Did they get a working demo completed within the allotted time?   Most Impactful Project —How does this changes the life of developers, employees, clients, partners, or end-users?   Best User Experience —Is it easy to interact and understand? How do you feel about using such it?   Most Innovative Solution — Could this be a radical innovation or a meaningful new take on an existing product or service?   The winners would get a special mug and all participants would receive some nice stickers and t-shirts.     Presentations At 6pm everybody had to stop coding and move to the presentation area.   For “Best Technical Achievement”, a team who built a home automation system using Raspberry Pi. They basically collect sensor data like temperature and humidity, then use WeDeploy to store that information. They also built a mobile app and web interface to display that data.   For “Most Impactful Project”, a web application that fetches JIRA tickets and generates release notes for you. This is a challenging problem to solve because it involves a big amount of tickets, but they built it in a way that was easy to read and digest.   For “Best User Experience”, a voice activated web app called Chicken Hands. The idea is to allow you to navigate through a recipe while you’re cooking. So you can hear pieces of a recipe and trigger commands using your voice like fetching the list of ingredients. They also used WeDeploy for hosting.   Finally, for “Most Innovative Solution”, a mobile app that calculates the traffic to work and auto-adjusts your alarm based on that traffic. That way you'll never be late to work again.     Judges But who decides who wins?   Well, we invited a special group of people to be our judges, that way we would have very different perspectives from different fields and cultures.   * JR Houn (Lead Senior Test Engineer in North America) * Vitor Fernandes (Design Coordinator in Latin America) * Bryan Cheung (Co-founder & Chief Executive Officer) * Chema Balsas (Principal Frontend Engineer based in Europe)     Thanks! This was not a only one man's work, many people made this possible, and I'd like to say thanks for everybody that helped organize this thing (specially Joshua Kuo) and all the participants who worked so hard on their ideas.   What about you? Are you planning to organize your own hack day? Any suggestions on how we can improve the next one? Feel free to leave a comment and share this with your friends! Zeno Rocha 2017-02-28T21:31:54Z
Categories: CMS, ECM

Nativescript: a hybrid mobile solution

Liferay - Tue, 02/28/2017 - 04:04

Hi community! I’m Sarai Díaz, Software Engineer working at Madrid’s office in the Liferay Screens team! :) This is my first blog post and I want to tell you something...

 

Native technology is a great choice to provide the best possible solution for your mobile customer experience but it’s not the only one. Nowadays there are many hybrid solutions like cross compiled, web based or javascript runtime. But, what does it means?

 

First, cross compiled means that you write the app in an specific language (let’s say Javascript or C#) and there is a compiler capable of creating the native code for your code. Then this native code will be compiled and packaged using the typical toolchain. Xamarin is the biggest framework in this group, but maybe you also remember Titanium.

 

The second way, web based way, such as Cordova (Ionic or PhoneGap). This way only uses HTML, CSS and Javascript to render the content and the Cordova layer allows you to call some native code.

 

The last way is the javascript runtime. You write the code in Javascript and this code runs in a Virtual Machine inside the device. Then, the API calls are dispatched to native APIs and after that, you can see the Android or iOS app doing what you requested. Nativescript is an example of this way.

 

Emil Öberg saw those ways to do mobile apps almost a year ago and he has a video speaking about that.

 

In summary, you can create apps simultaneously for both platforms, Android and iOS, and the app will look like native and nobody will realise that it's really hybrid ;)

 

The hybrid technology market is very fragmented right now and for that reason we have decided to keep an eye on some of the most popular frameworks like React Native, Nativescript, Ionic2 or Xamarin. We are creating little prototypes and different wrappers to use the native screenlets in an easy way with these hybrid frameworks.

 

I'm working on the Nativescript prototype and we have developed a small proof of concept that displays and uses the LoginScreenlet and the ImageGalleryScreenlet in both platforms, Android & iOS.

 

Pros and cons about hybrid solutions

Everything has pros and cons, right? Let’s see them!

 

If you want to create an app and you want to do it with hybrid technology, we just said that you can choose three ways: cross compiled, web based and javascript runtime.

 

If you choose cross compiled technology, you have to handling the first important issue which is the variations between UI controls on different platforms and their different ways they expect you to use them that alter the entire experience design. Also, code might not run as fast as native.

 

In other hand, if you choose web based technology, you can use your own tools. It means that you are not force to use a specific IDE to develop the app. You can use either a text editor or an IDE if you want some hints. But this fails to cope up with the expectations of building apps with offline capabilities and animation tools.

 

Finally, javascript runtime way, we said that you have to write your app in Javascript, which means that it executes all in the main thread. The operations that potentially take longer can lag the rendering of the UI and make the application look and feel slow. Also, if we want to target multiple platforms with a single codebase, some platform-specific features or styling may be unavailable or difficult to access.

 

So, if you are thinking about using a hybrid framework in the next project, you have to know that it’s an easy way for web developers because they already know the technology (HTML, CSS, Javascript) but you can have performance issues. On the other hand, it doesn’t matter what framework do you use, you can always reuse some code. But perhaps the biggest advantage is that hybrid reduces development costs.

 

Nativescript example

Now, you know more about hybrid solutions so, I think it’s time to see some code. You can see the Nativescript proof of concept here and the Liferay Screens plugin here. You can contribute to them too!

 

If you have any questions or doubts about this, please ask, don't be shy!

Sarai Diaz 2017-02-28T09:04:16Z
Categories: CMS, ECM

New content display application from Webtown for Liferay 6.2

Liferay - Mon, 02/27/2017 - 02:49

Webtown is proud to introduce you Smart Content, an upgraded application for Liferay 6.2!
 

 

Our portlet has many new features and properties that let you display your content in a smart, creative and flexible way.  

We gathered some of the best ones for you:

  • Better content selection logic for an easy and fast selection
  • Simplified content reordering with Drag&Drop
  • Manually selected contents displayed by template for bigger flexibility
  • Listing contents from indexer database for faster page loading
  • Search box for effective content filtering
  • Template-based (HTML) content list display (even a different template can be assigned to the first page of the list)

We provide you a 30 days free trial on Liferay Marketplace along with some further information, screenshots and contacts. We would be really happy to read about your opinion and remarks, please share them with us anytime!

Smart Content is available for Liferay CE 6.2 and soon will be for EE as well.

The Webtown Web Content Display portlet for Liferay 6.1 is also available on Marketplace.

Orsolya Kuti 2017-02-27T07:49:38Z
Categories: CMS, ECM

Service Builder 6.2 Migration

Liferay - Thu, 02/23/2017 - 22:50

I'm taking a short hiatus from the design pattern series to cover a topic I've heard a lot of questions on lately - migrating 6.2 Service Builder wars to Liferay 7 CE / Liferay DXP.

Basically it seems you have two choices:

  1. You can keep the Service Builder implementation in a portlet war. Any wars you keep going forward will have access to the service layer, but can you access the services from other OSGi components?
  2. You take the Service Builder code out into an OSGi module. With this path you'll be able to access the services from other OSGi modules, but will the services be available to the legacy portlet wars?

So it's that mixed usage that leads to the questions. I mean, if all you have is either legacy wars or pure OSGi modules, the decision is easy - stick with what you've got.

But when you are in mixed modes, how do you deliver your Service Builder code so both sides will be happy?

The Scenario

So we're going to work from the following starting point. We have a 6.2 Service Builder portlet war following a recommendation that I frequently give, the war has only the Service Builder implementation in it and nothing else, no other portlets. I often recommend this as it gives you a working Service Builder implementation and no pollution from Spring or other libraries that can sometimes conflict with Service Builder. We'll also have a separate portlet war that leverages the Service Builder service.

Nothing fancy for the code, the SB layer has a simple entity, Course, and the portlet war will be a legacy Liferay MVC portlet that lists the courses.

We're tasked with upgrading our code to Liferay 7 CE or Liferay DXP (pick your poison ), and as part of the upgrade we will have a new OSGi portlet component using the new Liferay MVC framework for adding a course.

To reduce our development time, we will upgrade our course list portlet to be compatible with Liferay 7 CE / Liferay DXP but keep it as a portlet war - basically the minimal effort needed to get it upgraded. We'll also have the new portlet module for adding a course.

But our big development focus, and the focus of this blog, will be choosing the right path for upgrading that Service Builder portlet war.

For evaluation purposes we're going to have to upgrade the SDK to a Liferay Workspace. Doing so will help get us some working 7.x portlet wars initially, and then when it comes time to do the testing for the module it should be easy to migrate.

Upgrading to a Liferay Workspace

So the Liferay IDE version 3.1 Milestone 2 is available, and it has the Code Upgrade Assistant to help take our SDK project and migrate it to a Liferay Workspace.

For this project, I've made the original 6.2 SDK project available at https://github.com/dnebing/sb-upgrade-62-sdk.

You can find an intro to the upgrade assistant in Greg Amerson's blog: https://web.liferay.com/web/gregory.amerson/blog/-/blogs/liferay-ide-3-1-milestone-1-released and Andy Wu's blog: https://web.liferay.com/web/andy.wu/blog/-/blogs/liferay-ide-3-1-milestone-2-released.

It is still a milestone release so it is still a work in progress, but it does work on upgrading my sample SDK. Just a note, though, it does take some processing time during the initial upgrade to a workspace; if you think it has locked up or is unresponsive, just have patience. It will come back, it will complete, you just have to give it time to do it's job.

Checkpoint

After you finish the upgrade, you should have a Liferay workspace w/ a plugins-sdk directory and inside there is the normal SDK directory structure. In the portlet directory the two portlet war projects are there and they are ready for deployment.

In fact, in the plugins-sdk/dist directory you should find both of the wars just waiting to be deployed. Deploy them to your new Liferay 7 CE or Liferay DXP environment, then spin out and drop the Course List portlet on a page and you should see the same result as the 6.2 version.

So what have we done so far? We upgraded our SDK to a Liferay Workspace and the Code Upgrade Assistant has upgraded our code to be ready for Liferay 7 CE / Liferay DXP. The two portlet wars were upgraded and built. When we deployed them to Liferay, the WAR -> WAB conversion process converted our old wars into OSGi bundles.

However, if you go into the Gogo shell and start digging around, you won't find the services defined from our Service Builder portlet. Obviously they are there because the Course List portlet uses it to get the list of courses.

War-Based Service Builder

So how do these war-based Service Builder upgrades work? If you take a look at the CourseLocalServiceUtil's getService() method, you'll see that it uses the good ole' PortletBeanLocator and the registered Spring beans for the Service Builder implementation. The Util classes use the PortletBeanLocator to find the service implementations and may leverage the class loader proxies (CLP) if necessary to access the Spring beans from other contexts. From the service war perspective, it's going through Liferay's Spring bean registry to get access to the service implementations.

Long story short, our service jar is still a service jar. It is not a proper OSGi module and cannot be deployed as one. But the question is, can we still use it?

OSGi Add Course Portlet

So we need an OSGi portlet to add courses. Again this will be another simple portlet to show a form and process the submit. Creating the module is pretty straight forward, the challenge of course is including the service jar into the bundle.

First thing that is necessary is to include the jar into the build.gradle dependencies. Since it is not in a Maven-like repository, we'll need to use a slightly different syntax to include the jar:

dependencies { compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "2.0.0" compileOnly group: "com.liferay.portal", name: "com.liferay.util.taglib", version: "2.0.0" compileOnly group: "javax.portlet", name: "portlet-api", version: "2.0" compileOnly group: "javax.servlet", name: "javax.servlet-api", version: "3.0.1" compileOnly group: "jstl", name: "jstl", version: "1.2" compileOnly group: "org.osgi", name: "osgi.cmpn", version: "6.0.0" compile files('../../plugins-sdk/portlets/school-portlet/docroot/WEB-INF/lib/school-portlet-service.jar') }

The last line is the key; it is the syntax for including a local jar file, and in our case we're pointing at the service jar which is part of the plugins-sdk folder that we upgraded.

Additionally we need to add the stanza to the bnd.bnd file so the jar gets included into the bundle during the build:

Bundle-ClassPath:\ .,\ lib/school-portlet-service.jar -includeresource:\ lib/school-portlet-service.jar=school-portlet-service.jar

As you'll remember from my blog post on OSGi Module Dependencies, this is option #4 to include the jar into the bundle itself and use it in the classpath for the bundle.

Now if you build and deploy this module, you can place the portlet on a page and start adding courses.  It works!

By including the service jar into the module, we are leveraging the same PortletBeanLocator logic used in the Util class to get access to the service layer and invoke services via the static Util classes.

Now that we know that this is possible (we'll discuss whether to do it this way in the conclusion), let's now rework everything to move the Service Builder code into a set of standard OSGi modules.

Migrating Service Builder War to Bundle

Our service builder code has already been upgraded when we upgraded the SDK, so all we need to do here is create the modules and then move the code.

Creating the Clean Modules

First step is to create a clean project in our Liferay workspace, a foundation for the Service Builder modules to build from.

Once again, I start with Blade since I'm an Intellij developer. In modules directory, we'll let Blade create our Service Builder projects:

blade create -t service-builder -p com.liferay.school school

For the last argument, use something that reflects your current Service Builder project name.

This is the clean project, so let's start dirtying it up a bit.

Copy your legacy service.xml to the school/school-service directory.

Build the initial Service Builder code from the service XML. If you're on the command line, you'd do:

../../gradlew buildService

Now we have unmodified, generated code. Layer in the changes from the legacy Service Builder portlet, including:

  • portlet-model-hints.xml
  • service.properties
  • Changes to any of the META-INF/spring xml files
  • All of your Impl java classes

Rebuild services again to get the working module code.

Module-Based Service Builder

So we reviewed how the CourseLocalServiceUtil's getService() method in the war-based service jar leveraged the PortletBeanLocator to find the Spring bean registered with Liferay to get the implementation class.

In our OSGi module-based version, the CourseLocalServiceUtil's getService() method is instead using an OSGi ServiceTracker to get access to the DS components registered in OSGi for the implementation class.

Again the service "jar" is still a service jar (well, module), but we also know that the add course portlet will be able to leverage the service (with some modifications), the question of course is whether we can also use the service API module in our legacy course list portlet.

Fixing the Course List Portlet War

So what remains is modifying the course list portlet so it can leverage the API module in lieu of the legacy Service Builder portlet service jar.

This change is actually quite easy...

The liferay-plugin-package.properties file changed from the upgrade assistant contains the following:

required-deployment-contexts=\ school-portlet

This is the line used by the Liferay IDE to inject the service jar so the service will be available to the portlet war. We need to edit this line to strip out these two lines since we're not using the deployment context.

If you have the school-portlet-service.jar file in docroot/WEB-INF/lib, go ahead and delete that file since it is no longer necessary.

Next comes the messy part; we need to copy in the API jar into the course list portlet's WEB-INF/lib directory. We have to do this so Eclipse will be happy and will be able to happily compile all of our code that uses the API. There's no easy way to do this, but I can think of the following options:

  1. Manually copy the API jar over.
  2. Modify the Gradle build scripts to add support for the install of artifacts into the local Maven repo, then the Ivy configuration for the project can be adjusted to include the dependency. Not as messy as a manual file copy, but involves doing the install of the API jar so Ivy can find it.

We're not done there... We actually cannot keep the jar in WEB-INF/lib otherwise at runtime you get class cast exceptions, so we need to exclude it during deployment. This is easily handled, however, by adding an exclusion to your portal-ext.properties file:

module.framework.web.generator.excluded.paths=<CURRENT EXCLUSIONS>,\ WEB-INF/lib/com.liferay.school.api-1.0.0.jar

When the WAR->WAB conversion is taking place, it will exclude this jar from being included. So you get to keep it in the project and let the WAB conversion strip it out during deployment.

Remember to keep all of the current excluded paths in the list, you can find them in the portal.properties file included in your Liferay source.

Build and deploy your new war and it should access the OSGi-based service API module.

Conclusion

Well, this ended up being a mixed bag...

On one hand I've shown that you can use the Service Builder portlet's service jar as a direct dependency in the module and it can invoke the service through the static Util classes defined within. The advantage of sticking with this path is that it really doesn't require much modification from your legacy code beyond completing the code upgrade, and the Liferay IDE's Code Upgrade Assistant gets you most of the way there. The obvious disadvantage is that you're now adding a dependency to the modules that need to invoke the service layer and the deployed modules include the service jar; so if you change the service layer, you're going to have to rebuild and redeploy all modules that have the service jar as an embedded dependency.

On the other hand I've shown that the migrated OSGi Service Builder modules can be used to eliminate all of the service jar replication and redeployment pain, but the hoops you have to jump through for the legacy portlet access to the services are a development-time pain.

It seems clear, at least to me, that the second option is the best. Sure you will incur some development-time pain to copy service API jars if only to keep the java compiler happy when compiling code, but it definitely has the least impact when it comes to service API modifications.

So my recommendations for migrating your 6.2 Service Builder implementations to Liferay 7 CE / Liferay DXP are:

  • Use the Liferay IDE's Code Upgrade Assistant to help migrate your code to be 7-compatible.
  • Move the Service Builder code to OSGi modules.
  • Add the API jars to the legacy portlet's WEB-INF/lib directory for those portlets which will be consuming the services.
  • Add the module.framework.web.generator.excluded.paths entry to your portal-ext.properties to strip the jar during WAR->WAB conversion.

If you follow these recommendations your legacy portlet wars will be able to leverage the services, any new OSGi-based portlets (or JSP fragments or ...) will be able to access the services, and your deployment impact for changes will be minimized.

My code for all of this is available in github:

Note that the upgraded code is actually in the same repo, they are just in different branches.

Good Luck!

Update

After thinking about this some more, there's actually another path that I did not consider...

For the Service Builder portlet service jar, I indicated you'd need to include this as a dependency on every module that needed to use the service, but I neglected to consider the global service jar option that we used for Liferay 6.x...

So you can keep the Service Builder implementation in the portlet, but move the service jar to the global class loader (Tomcat's lib/ext directory). Remember that with this option there can only be one service jar, the global one, so no other portlet war nor module (including the Service Builder portlet war) can have a service jar. Also remember that to update a global service jar, you can only do this while Tomcat is down.

The final step is to add the packages for the service interfaces to the module.framework.system.packages.extra property in portal-ext.properties. You want to add the packages to the current list defined in portal.properties, not replace the list with just your service packages.

Before starting Tomcat, you'll want to add the exception, model and service trio to the list. For the school service example, this would be something like:

module.framework.system.packages.extra=\ <ALL DEFAULT VALUES COPIED IN>,\ com.liferay.school.exception,\ com.liferay.school.model,\ com.liferay.school.service

This will make the contents of the packages available to the OSGi global class loader so, whether bundle or WAB, they will all have access to the interfaces and static classes.

This has a little bit of a deployment process change to go with it, but you might consider this the least impactful change of all. We tend to frown on the use of the global class loader because it may introduce transitive dependencies and does not support hot deployable updates, but this option might be lower development cost to offset the concern.

David H Nebinger 2017-02-24T03:50:13Z
Categories: CMS, ECM

Liferay OSGi注解(Annotation) - 使用手册(译文)

Liferay - Tue, 02/21/2017 - 00:50
原文:https://web.liferay.com/web/user.26526/blog/-/blogs/liferay-osgi-annotations-what-they-are-and-when-to-use-them   原文作者: DAVID H NEBINGER     当你查看Liferay 7 CE/Liferay DXP源码时,你会看到大量不同的注解。当你除此看到这些注解的时候,可能会感觉到有些无所适从。所以我想写一些引用指导来解释这些注解是什么,并且在你自己的OSGi代码中什么时候使用比较合适。   我们开始吧...   @Component   在OSGi世界中,这种注解用于定义“声明式服务(Declarative Service)”。声明式服务是OSGi中用于动态生成服务。它使容器中的大量的组件(component)间可以互相关联调用。   在Component注解中有三个组要属性:
  • immediate - 通常设置为true。用于使组件在部署后直接启动(start),不用等待其他引用或者使用懒加载(lazy startup)。
  • properties - 用设置一系列OSGi属性绑定到组件。这些属性对于当前组件是可见的,但是更重要的是它们对于其他组件也是可见的。这些组件可以帮助配置组件,也可以用于支持组件过滤。
  • service - 定义组件实现的服务。有时这个属性是可选的,但是通常是必要的,因为这样可以使组件要实现服务更明确。service的值通常是一个接口,但是也可以使用一个实体类。
什么时候需要使用@Component?只要需要在OSGi容器中使用要发布一个组件的时候,就可以使用。不是所有的类都需要是组件。只是当你需要将一个插件植入到Liferay环境中的时候才会声明一个组件。(例如,添加一个导航项、定义一个MVC command handler、覆写一个Liferay组件或者为自己的扩展框架写一个插件)。   @Reference   这个注解是和@Component相对应的。@Reference用于获取OSGi容器中其他的组件并且注入到你自己的组件中。需要注意的是,因为OSGi在做注入的工作,你只能注入OSGi组件类。@Reference注解会被非组件类忽略,并且也会组件的被子类忽略。对于所有的引用注入,都必须在@Component类中声明。 当你定义一个基类时注入了一些其他的服务,并且这个基类没有使用@Component注解(因为定义时还没有完成),@Reference注解会被非组件类忽略,这样的情况下,所有的注入都是无效的。最终,所有的setter方法和@Reference注解都需要复制到实习子类中。这样显得相当冗余。需要注意这一点。 可能@Reference最常见的属性是“unbind”属性了。在setter方法中,经常会看见@Reference(unbine="-")这样的写法。当你为setter方法使用@Reference时,OSGi使用使用这个setter方法作为组件的setter方法。unbind属性指定了当组件释放是,不需要调用任何其他的方法。也就是说,不需要为组件释放做任何的处理。多数情况下,这么做没有问题,服务器启动,OSGi绑定组件,并且使用组件一直到系统关闭。 另外一个属性是“target”,Target用于支持过滤。还记得@Component中的属性吧?通过使用target属性,可以通过特定查询语法指定一类组件。 例如: @Reference( target = "(javax.portlet.name=" + NotificationsPortletKeys.NOTIFICATIONS + ")", unbind = "-" ) protected void setPanelApp(PanelApp panelApp) { _panelApp = panelApp; } 这段代码希望获取PanelApp组件的实例,但是它却指定了Notification portlet中的PanelApp组件。所以其他portlet中的PanelApp不符合条件,只有Notification portlet中的PanelApp才符合条件。 我们这里讨论的属性有时候会很重要,所以我会详细讨论这些属性。 Cardinality 第一个是cardinality属性,默认值是ReferenceCardinality.MANDITORY,可选值有:OPTIONAL、MULTIPLE和AT_LEAST_ONE。这些值的意义是:
  • MANDITORY - 引用必须在组件启动前可用并且注入。
  • OPTIONAL - 引用在组件启动阶段时不是必要的,在不指定组件的时候也是可以正常工作的。
  • MULTIPLE - 有多种不同的资源可以引用,组件会使用全部的方法。和OPTIONAL相似,在组件启动阶段,引用不是不要的。
  • AT_LEAST_ONE - 多种资源可以满足引用,组件会全部使用。但是在组件启动时,至少有一个资源是可用的。
Multiple选项可以让你通过引用,使用多种符合条件的方法调用。这种方式,只有在使用setter方法中@Reference注解,并且setter方法是向列表或者数组中添加内容的情况下才合理。或者可以使用ServiceTracker替换这种写法,这样你就不用亲自手动去管理列表了。   Opional可以使组件在启动时不必须指定某个引用。在有循环引用问题时,这种方法就会帮助你解决问题。例如:A引用B,B引用C,C引用A。如果这三个组件都设置引用为REQUIRED,所有组件都不会启动,因为它们都在等待其他组件满足条件(只有已经启动的组件才能指派给@Reference)。为引用使用optional选项就打破了这种循环,组件就可以正常启动,并且引用问题也解决了。   Policy 下一个重要的@Reference属性是policy。Policy的值可以是ReferencePolicy.STATIC (默认)或者ReferencePolicy.DYNAMIC。他们的意义是:
  • STATIC - 只有在已经指派了引用之后,组件才能启动。在启动之后,当出现其他可用引用时,组件也不会理会。
  • DYNAMIC - 无论有没有可用的引用,组件都会启动。并且在有新的可用引用的时候,组件会使用新的引用。
引用策略控制着在组件启动后,当新的引用资源可用的时候的使用策略。总体来说,使用STATIC,组件会忽略新的引用,使用DYNAMIC,当出现新的可用引用时,组件会改变引用。   PolicyOption 和policy一同使用的另外一个属性是policyOption。这个属性的值可以是ReferencePolicyOption.RELUCTANT (默认) 或者 ReferencePolicyOption.GREEDY。他们的意思是:
  • RELUCTANT - 对于单一(single)的引用,新的可用引用会被忽略。对于多项(multiple)引用,新的可用引用出现的时候会被绑定。
  • GREEDY - 只要新的可用引用出现的时候,组件就会绑定这些引用。.
  这些选项组合起来有很多种方式。 首先是默认的,ReferenceCardinality.MANDITORY + ReferencePolicy.STATIC + ReferencePolicyOption.RELUCTANT。 这样组合是组件一定要一个引用可用才能启动,并且忽略新的可用引用。这样的默认组和确保了组件的稳定性。 另外一种组合是ReferenceCardinality.OPTIONAL/MULTIPLE + ReferencePolicy.DYNAMIC + ReferencePolicyOption.GREEDY。 在这样的配置中,组件在缺少服务引用的时候也会正常使用,但是组件在使用过程中允许新的引用和引用变更,在新的引用可用时,组件会主动的绑定引用服务。 也会有其他的组合,但是在设置的时候需要了解这样的设置对组件的影响。毕竟在你声明引用的时候你要了解如何是组件工作。你需要考虑到组件在没有引用的时候如何响应,如果服务不可用的时候组,件是否需要停止工作。在你考虑问题的时候不信要考虑理想情况,也要考虑到特殊情况,例如重新部署、卸载、服务差距和组件的容错性。如果这些问题都能解决,那么组件就是比较理想的。 最后,回想一下,什么时候需要使用@Reference注解?就是你需要从OSGi环境中向你的组件注入服务的时候。这些服务可以是你自己的服务,也可以是OSGi容器中其他模块的服务。记住,@Reference只能在OSGi组件中使用,但是你可以使你的类通过@Component注解变成组件。   @BeanReference 这个是一个Liferay注解,用于向Spring bean中注入一个Liferay core中的引用。   @ServiceReference 这是一个Liferay注解,用于向组件中注入一个引用,这个引用是来自于Spring Extender module bean。   稍等!三种引用注解?我需要用哪一种? 我们来解释一下这三种引用注解。根据我的经验来判断,多数情况下,你需要使用@Reference注解。Liferay core Spring beans和Spring Extender module beans同样也是暴露在OSGi容器中的,所以@Reference在多数情况下是没问题的。 如果在使用@Reference的时候,服务没有被注入,并且返回null,这就意味着你可能需要使用其他的引用注解了。选择哪种注解原则不难:如果bean是在Liferay core中,就是用@BeanReference;反之,但是如果是在Spring Extender module中,就是用@ServiceReference注解。注意,无论是bean或者service注解都会要求你的组件使用Spring Extender。如何引用依赖,参考任何使用ServiceBuilder的服务模块,查看build.gradle和bnd.bnd,用同样的方法修改你自己的模块。   @Activate @Activate注解是对应Spring的InitializingBean接口。它声明了组件在启动是要调用的方法。在Liferay源码中,你会看到它会被三个主要的方法使用: @Activate protected void activate() { ... } @Activate protected void activate(Map<String, Object> properties) { ... } @Activate protected void activate(BundleContext bundleContext, Map<String, Object> properties) { ... } 也有其他的方法使用这个注解,只要在源码中搜索@Activate就可以找到很多不同的用例了。除了无参数的activate方法,其他的都依赖于OSGi所注入的值。注意properties映射实际是从你的OSGi的Configuration Admin服务取得的。   什么时候需要使用@Activate呢?只要你需要在组件启动后、被使用前需要做一些初始化操作的时候就可以使用。例如,我曾经设置Quartz计划任务,验证数据库实体的时候使用过。   @Deactivate @Dactivate注解是和@Ativate注解相反的,它定义了组件在停用是需要调用的方法。   @Modified @Modified注解定义了当组件被改变时需要调用的方法。特别是在标记@Reference了的方法被改变的时候。在Liferay源码中,@Modified注解经常是和标记@Activate的方法绑定在一起的,这样同一个方法就能同时处理启动和改变了。   @ProviderType @ProviderType是BND中使用的,通常是在考虑将head包含的复杂情况时使用。长话短说,@ProviderType是被BND使用,用来定义在实现类中可以指派的OSGi manifest的版本。并且它尝试限制组件版本范围的使用。   它的重点是用来确定接口的改变,通过为实现类限制的版本,会强制实现类来根据接口来进行更新。   什么时候使用@ProviderType呢?其实,并不一定需要使用。你可以看见,在ServiceBuilder生成的代码里面已经被使用了。我在这里提到这个注解的原因并不是因为你一定要使用它,而是满足你的好奇心。   @ImplementationClassName 这个是Liferay中为ServiceBuilder实体接口使用的注解。它定义了在service module中用来实现接口的类。 这个你并以需要使用,只是为了让你知道它是做什么的的。   @Transactional 这是另一个ServiceBuilder服务接口使用的注解。它定义了服务方法的事务需求。 这个方法在你开发的时候也用不到。   @Indexable @Indexable用来修饰会使搜索索引更新你的方法,特别是ServiceBuilder中的add、update和delete实体的方法。 你可以为你的实现增、删、改的方法使用@Indexable注解。如果实体关联com.liferay.portal.kernel.search.Indexer 相关的实现方法,那么实体就可以被索引。   @SystemEvent @SystemEvent注解是在ServiceBuilder生成的代码中被可能生成系统事件的方法使用的。系统事件和staging、LAR和导入导出处理等相关。例如,当一个web conteng被删除,这个就会生成一个SystemEvent记录。在staging环境中,当“Publish to Live”原型是,删除SystemEvent确保了相关联的web content在live站点中也被删除。 需要什么时候使用@SystemEvent注解呢?说实话,我也不知道。在我10年的经验中,我从来没有需要生成SystemEvent记录的时候,也从来没更改过Liferay发布和LAR处理。如果任何人有相关经验使用@SystemEvent注解的话,我很愿意侧耳恭听。   @Meta OSGi有一个基于XML的系统用于为Configuration Admin定义配置详细信息。BND项目的通过使用@Meta注解,可以使BND根据配置接口中使用这个注解的方法生成配置文件。   重要提示:一定要在bnd.bnd文件中添加下行代码才能使用@Meta注解: -metatype: * 如果没添加的话,在生成XML配置文件的时候,是不会用到@Meta注解的。   @Meta.OCD 这个注解用于“Object Class Definition”方面的配置详细信息。这个注解用于为在接口层为类的定义提供id,名字和语言等详细信息。 什么时候使用这个注解呢?当为组件定义一个Configuration Admin接口时,并且这个接口是在Control Panel -> System Setting有一个配置选项的时候使用。   注意@Meta.OCD属性包含了本地化的设置。这样就可以使用resource bundle来翻译配置名称、详细配置信息和@ExtendedObjectClassDefinition分类了。   @Meta.AD 这个注解用于“Attribute Definition”,用于定义配置中表单项层面的定义。注解用于为表单项提供ID、名称、说明、默认值和其他详细信息。   什么时候使用这个注解?就是在需要为System Setting中的配置提供更多关于配置项目细节的时候使用。   @ExtendedObjectClassDefinition 这个是Liferay的注解,用于定义配置的类型(就是在System Setting中上面显示的那些分类)和配置的范围。   范围可以是下面的值:
  • SYSTEM - 整个系统中的全局配置,在生个系统中只有一个配置。
  • COMPANY - Company级,每个portal实例中只可以有一个配置。
  • GROUP - Group(站点)级,每个站点中只可以有一个配置。
  • PORTLET_INSTANCE - 这个和portlet实例参数类似,每个portlet实例中都会有一分配置。
什么时候要用到这个注解呢?每次用到@Meta.OCD注解的时候,都需要用到一次@ExtendedObjectClassDefinition注解来定义配置的分类。   @OSGiBeanProperties 这是一个Liferay的注解,用来定义OSGi组件属性,这些属性用来注册Spring bean为一个OSGi组件。你会在ServiceBuilder模块中见到这个注解被使用,将Spring bean暴露给OSGi容器。记着,ServiceBuilder依然是基于Spring的(SpringExtender),这个注解就是用来将Spring bean注册为OSGi组件用的。   什么时候会用到这个注解呢?如果你在你自己的模块中使用了Spring Extender来使用Spring,并且你想将Spring bean在OSGi容器中暴露为组件(这么做可以使其他模块使用这个Spring bean),这个时候你就需要使用这个注解了。   我没有在这里讨论更多的细节,因为这个注解可以在javadoc中被大量的找到。查看这个例子: https://github.com/liferay/liferay-portal/blob/master/portal-kernel/src/com/liferay/portal/kernel/spring/osgi/OSGiBeanProperties.java   总结   这就是我在Liferay 7 CE / Liferay DXP中见到的所有注解了。希望这些信息可以帮到你的Liferay开发。如果你发现本文没有涉及的注解或者希望了解更多细节,请随时向原文博客或者在这里提问。 Neil Jin 2017-02-21T05:50:17Z
Categories: CMS, ECM

Farewell Juan!

Liferay - Fri, 02/17/2017 - 15:44
Farewell Juan!

Juan Gonzalez announced that today is his last day as a Liferay employee. While he’ll still be part of the Liferay community, I think this is a nice opportunity for us to thank him for his work at Liferay and to wish him well on his next endeavor.

Juan,
After working with you for several years, I’m sad to see you go. You’re an incredibly passionate and hard worker. Thanks to your dedication, Liferay 7 correctly supports several servlet features (many of which were required for Liferay Faces to be compatible with Liferay 7). Thanks to your passion, Liferay Faces developers can access portal taglib features through tags like portal:inputSearch (not to mention all the Liferay Faces Portal bugs you’ve fixed). Thanks to your involment in the forums, countless people in the Liferay community have had their problems solved (you’ve written almost 3k posts and are user #4 overall).

Juan, the Liferay community, the Liferay Faces project, and Liferay itself would not be nearly as great without your contributions. And I’ve personally admired and sought to emulate your productivity, passion, and community involvement. Thanks for all your hard work!

Farewell Juan!

- Kyle

Kyle Joseph Stiemann 2017-02-17T20:44:59Z
Categories: CMS, ECM

Liferay Design Patterns - Multi-Scoped Data/Logic

Liferay - Fri, 02/17/2017 - 10:33
Pattern: Multi-Scoped Data/Logic Intent

The intent for this pattern is to support data/logic usage in multiple scopes. Liferay defines the scopes Global, Site and Page, but from a development perspective scope refers to Portal and individual OSGi Modules. Classic data access implementations do not support multi-scope access because of boundaries between the scopes.

The Multi-Scoped Data/Logic Liferay Design Pattern's intent is to define how data and logic can be designed to be accessable from all scopes in Liferay, either in the Portal layer or any other deployed OSGi Modules.

Also Known As

This pattern is implemented using the Liferay Service Builder tool.

Motivation

Standard ORM tools provide access to data for servlet-based web applications, but they are not a good fit in the portal because of the barriers between modules in the form of class loader and other kinds of boundaries. If a design starts from a standard ORM solution, it will be restricted to a single development scope. Often this may seem acceptable for an initial design, but in the portal world most single-scoped solutions often need to be changed to support multiple scopes. As the standard tools have no support for multiple scopes, developers will need to hand code bridge logic to add multi-scope support, and any hand coding increases development time, bug potential, and time to market.

The motivation for Liferay's Service Builder tool is to provide an ORM-like tool with built-in support for multi-scoped data access and business logic sharing. The tool transforms an XML-based entity definition file into layered code to support multiple scopes and is used throughout business logic creation to add multi-scope exposure for the business logic methods.

Additionally the tool is the foundation for adding portal feature support to custom entities, including:

  • Auto-populated entity audit columns.
  • Asset framework support (comments, rankings, Asset Publisher support, etc).
  • Indexing and Search support.
  • Model listeners.
  • Workflow support.
  • Expando support.
  • Dynamic Query support.
  • Automagic JSON web service support.
  • Automagic SOAP web service support.

You're not going to get this kind of integration from your classic ORM tool...

And with Liferay 7 CE / Liferay DXP, additionally you also get an OSGi-compatible API and service bundle implementation ready for deployment.

Applicability

IMHO Service Builder applies when you are dealing with any kind of multi-scoped data entities and/or business logic; it also applies if you need to add any of the indicated portal features to your implementation.

Participants

The participants in this pattern are:

  • An XML file defining the entities.
  • Spring configuration files.
  • Implementation class methods to add business logic.
  • Service consumers.

The participants are used by the Service Builder tool to generate code for the service implementation details.

Details for working with Service Builder are covered in the following sections:

Collaboration

ServiceBuilder uses the entity definition XML file to generate the bulk of the code. Custom business methods are added to the ServiceImpl and LocalServiceImpl classes for the custom entities and ServiceBuilder will include them in the service API.

Consequences

By using Service Builder and generating entities, there is no real downside in the portal environment. Service Builder will generate an ORM layer and provide integration points for all of the core Liferay features.

There are three typical arguments used by architects and developers for not using Service Builder:

  • It is not a complete ORM. This is true, it does not support everything a full ORM does. It doesn't support Many To Many relationships and it also doesn't handle automatic parent-children relationships in One To Many. All that means is the code to handle many to many and even some one to many relationship handling will need to be hand-coded.
  • It still uses old XML files instead of newer Annotations. This is also true, but this is more a reflection of Liferay generating all of the code including the interfaces. With Liferay adding portal features based upon the XML definitions, using annotations would require Liferay to modify the annotated interface and cause circular change effects.
  • I already know how to develop using X, my project deadlines are too short to learn a new tool like Service Builder. Yes there is a learning curve with Service Builder, but this is nothing compared to the mountains of work it will take getting X working correctly in the portal and some Liferay features will just not be options for you without Service Builder's generated code.

All of these arguments are weak in light of what you get by using Service Builder.

Sample Usage

Service Builder is another case of Liferay eating it's own dogfood. The entire portal is based on Service Builder for all of the entities in all of the portlets, the Liferay entities, etc.

Check out any of the Liferay modules from simple cases like Bookmarks through more complicated cases such as Workflow or the Asset Publisher.

Conclusion

Service Builder is a must-use if you are going to do any integrated portal development. You can't build the portal features into your portlets without Service Builder usage.

Seriously. You have no other choice. And I'm not saying this because I'm a fanboy or anything, I'm coming from a place of experience. My first project on Liferay dealt with a number of portlets using a service layer; I knew Hibernate but didn't want to take time out to learn Service Builder. That was a terrible mistake on my part. I never did deal with the multi-scoping well at all, never got the kind of Liferay integration that would have been great to have. Fortunately it was not a big problem to have made such a mistake, but I learned from it and use Service Builder all the time now in the portal.

So I share this experience with you in hopes that you too can avoid the mistakes I made. Use Service Builder for your own good!

David H Nebinger 2017-02-17T15:33:26Z
Categories: CMS, ECM

Liferay IDE 3.1 Milestone 2 Released

Liferay - Thu, 02/16/2017 - 20:56

Hi all,

We are happy to say that we have the new milestone for Liferay IDE 3.1 released as described in section Updates and Feedback in Liferay IDE 3.1 Milestone 1 Released.

Go to http://releases.liferay.com/tools/ide/latest/milestone/ to install the updatesite.

If you want to download full Eclipse Neon bundled with Liferay IDE, just go to this page.

The only one obvious feature in milestone is Maven Support In Code Update Tool.

You can put your 6.2 maven root project path in the second page in Code Update Tool, and click “Import Projects” button.


And there is a new page called “Upgrade POM Files” added as the third page. Also we moved the “Find Breaking Changes” page before “Update Descriptor Files” page.


In the third page, you can search all pom.xml files in current Eclipse workspace and preview the changes Code Upgrade Tool is going the make and then either upgrade them one by one or all at once.  Be sure to double click the file to see what changes are going to be made by the tool.  

 

 

There are few more features added.

Add ability to customize bundle URL when importing a Liferay Workspace Project



Deploy Error Tooltip on Liferay Server

 

When some project build error after some changes, hover on the server, you can see the detail information of the error.

 


Next Release

Our next release version will be 3.1 m3 and will come up with more helpful features, e.g. maven type liferay workspace support, new JSF portlet wizard, migrate legacy service builder project, source lookup fixing in  Liferay 7x Server Launches.


Please goto community forums if you have any questions. We will try our best to help.


Regards. Andy Wu 2017-02-17T01:56:14Z
Categories: CMS, ECM

Improving Test Performance on Liferay

Liferay - Wed, 02/15/2017 - 13:26
Improving Test Performance on Liferay

Recently, we upgraded the JSF Portlet Bridge Test Compatibility Kit (TCK) from Selenium 1.0 to our new test framework which uses Selenium 2.53. The TCK contains about 220 tests, and on Liferay 7.0 before we upgraded, it took around 8 minutes and 30 seconds to execute. In contrast, the TCK took 1 minute and 30 seconds to run on Apache Pluto, the portlet container reference implementation. In order to speed up test execution for Liferay Portal, we decided to try a few simple tricks and changes to reduce the total test time, and… we succeeded! Here’s a breakdown for how fast each browser ran the TCK on my machine before our upgrade, after our upgrade, and after we tweaked the TCK with some Liferay specific tricks:

Browser Selenium 1.0 Test Time Selenium 2.53 Test Time Selenium 2.53 w/Exclusive
Window State Test Time HtmlUnit* - - ~00:00:45 Chrome - ~00:04:30 ~00:01:30 Firefox ~00:08:30 (w/FF v21.0) ~00:06:00 (w/FF v46.0) ~00:02:30 JBrowser*
(experimental) - - ~00:02:30 PhantomJS* - ~00:16:15 ~00:10:30

* Headless browser.

As you can see, we made some pretty big improvements just by upgrading to a modern version of Selenium. Running tests with HtmlUnit also provided a nice boost over other browsers. Before I talk in-depth about HtmlUnit though, I want to begin by explaining the Liferay-specific tweaks and tricks that we used to speed up the TCK. These techniques are specific to Liferay but not to Selenium or HtmlUnit, so they may be useful in improving the performance of Liferay portlet tests regardless of the test framework or browsers used.

Exclusive Window State

The main performance boost is thanks to Liferay’s custom “exclusive” window state.1 In Liferay, any portlet can be accessed in the exclusive state with a render URL containing the portlet’s id (p_p_id) and p_p_state=exclusive:

http://localhost:8080/my/portlets/page?p_p_id=myPortletName_WAR_myPortletWarName&p_p_lifecycle=0&p_p_state=exclusive

Liferay’s exclusive window state feature was created when Liferay only supported Portlet 1.0, and it provides similar functionality to the RESOURCE_PHASE of the Portlet 2.0 lifecycle. When Liferay Portal returns a portlet’s markup in the exclusive state, the markup contains only the portlet’s markup fragment without <html>, <head>, or <body> tags. Thankfully, every browser we use for testing handles the incomplete markup gracefully and renders the portlet testable. Providing the bare-bones portlet markup, the exclusive state doesn’t render any portal markup or frontend resources (such as CSS or JS). This greatly reduces the time it takes for a browser to load the page. The exclusive window state is useful for quickly testing backend functionality and rendering. I would not recommend testing portlets with complex JavaScript or CSS in the exclusive state. In fact, if you want to test a portlet with any external JavaScript resources at all, you will need to make sure that the resource’s script tag is rendered in the portlet’s body (<div>) markup rather than the portal’s <head> section (which isn’t rendered).2 Certainly, using the exclusive state will not work for all tests, but it can provide significant speed improvements for certain tests.

Pop Up Window State

If you cannot easily move your portlet’s resources into your portlet’s body or if you rely on Liferay Portal’s frontend features (JS and/or CSS), try using the “pop_up” window state instead. In Liferay, any portlet can be accessed in the pop up state with a render URL containing the portlet’s id (p_p_id) and p_p_state=pop_up:

http://localhost:8080/my/portlets/page?p_p_id=myPortletName_WAR_myPortletWarName&p_p_lifecycle=0&p_p_state=pop_up

When a portlet is in the pop up state, the portal renders the <html>, <head>, and <body> tags including JavaScript and CSS resources. However, as with the exclusive state, the portal does not render any portal markup or portlets besides the one referenced in the URL. Even though using the exclusive state yielded greater performance benefits, using the pop up state still significantly sped up our tests (probably by about 25%).

Of course, neither of these two states should be used for testing portlets which may interact with each other, since they only render a single portlet. These states also don’t help if you are trying to test other window states (as we do in the TCK). However, while upgrading the TCK, we found another way you can speed up your tests if you are using Selenium.

HtmlUnit

Of all the Selenium compatible browsers that we test with, HtmlUnit is by far the fastest. And since HtmlUnit is headless, it can be run on a CI server without a window manager. HtmlUnit is not perfect. Its JavaScript engine has trouble running more complicated or cutting edge code, so I wouldn’t recommend it for testing newer browser features like the History API (which SennaJS uses) or HTML5. Nonetheless, it is an excellent browser for testing simple pages quickly. So how do you use HtmlUnit? Well if you are using Selenium, simply add the HtmlUnit dependency to your project (make sure you get the latest one):

<dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>htmlunit-driver</artifactId> <version>2.23.2</version> <scope>test</scope> </dependency>

Then just change your WebDriver implementation to HtmlUnitDriver:

WebDriver webDriver = new HtmlUnitDriver();

The End.

Well… not really. HtmlUnit is a simple tool, but unfortunately configuring it to behave like every other browser is over-complicated and poorly documented. First, you will need to specify the following dependencies to avoid several NoClassDefFoundError/ClassNotFoundException issues:

<dependency> <groupId>xml-apis</groupId> <artifactId>xml-apis</artifactId> <version>1.4.01</version> <scope>test</scope> </dependency> <dependency> <groupId>org.eclipse.jetty.websocket</groupId> <artifactId>websocket-client</artifactId> <version>9.2.18.v20160721</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> <scope>test</scope> </dependency>

Second, I recommend disabling (or filtering) HtmlUnit’s incredibly verbose logging:

// Uncomment to enable HtmlUnit's logs conditionally when the log level is FINER or higher. // if (logLevel.intValue() > Level.FINER.intValue()) { LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog"); Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF); Logger.getLogger("org.apache.commons.httpclient").setLevel(Level.OFF); // }

Third, you should extend HtmlUnitDriver:

public class CustomHtmlUnitDriver extends HtmlUnitDriver {

Extending HtmlUnitDriver allows you to force HtmlUnit not to throw exceptions when JavaScript errors occur, and it allows you to silence CSS errors:

@Override protected WebClient modifyWebClient(WebClient initialWebClient) { WebClient webClient = super.modifyWebClient(initialWebClient); // Don't throw exceptions when JavaScript Errors occur. webClient.getOptions().setThrowExceptionOnScriptError(false); // Uncomment to filter CSS errors. // if (logLevel.intValue() > Level.FINEST.intValue()) { webClient.setCssErrorHandler(new SilentCssErrorHandler()); // } return webClient; }

Fourth, you should note that HtmlUnit does not load any images by default,3 so any tests which require images to be loaded should manually call a method like the one below to load them:

public void loadImages() { HtmlPage htmlPage = (HtmlPage) lastPage(); DomNodeList<DomElement> imageElements = htmlPage.getElementsByTagName("img"); for (DomElement imageElement : imageElements) { HtmlImage htmlImage = (HtmlImage) imageElement; try { // Download the image. htmlImage.getImageReader(); } catch (IOException e) { // do nothing. } } }

Finally, always initialize HtmlUnit with JavaScript enabled (and emulate a popular browser):

WebDriver webDriver = new CustomHtmlUnitDriver(BrowserVersion.FIREFOX_45, true);

If you want a complete example of how we use HtmlUnit in Liferay Faces, see HtmlUnitDriverLiferayFacesImpl.java and Browser.java.

Hopefully, the advice in this post will help you speed up your tests in Liferay. If you’ve found any other tricks that improve your tests’ performance, please post them in the comments below.

  1. Liferay Faces Team Lead, Neil Griffin, suggested using the exclusive window state to speed up tests.
  2. Liferay Faces Bridge automatically handles this case and moves JS and CSS resource markup into the portlet’s body (<div>) if the exclusive state is being used.
  3. Once HtmlUnit 2.25 and a compatible HtmlUnitDriver are released, you will be able to configure HtmlUnit to download all images automatically.
Kyle Joseph Stiemann 2017-02-15T18:26:41Z
Categories: CMS, ECM

Liferay Design Patterns - Flexible Entity Presentation

Liferay - Wed, 02/15/2017 - 09:18
Introduction

So I'm going to start a new type of blog series here covering design patterns in Liferay.

As we all know:

In software engineering, a software design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. - Wikipedia

In Liferay, there are a number of APIs and frameworks used to support Liferay-specific general reusable solutions. But since we haven't defined them in a design pattern, you might not be aware of them and/or if/when/how they could be used.

So I'm going to carve out some time to write about some "design patterns" based on Liferay APIs and frameworks. Hopefully they'll be useful as you go forward and designing your own Liferay-based solutions.

Being a first stab at defining these as Liferay Design Patterns, I'm expecting some disagreement on simple things (that design pattern name doesn't seem right) as well as some complex things... Please go ahead and throw your comments at me and I'll make necessary changes to the post. Remember this isn't for me, this is for you. 

And I must add that yes, I'm taking great liberties in using the phrase "design pattern". Most of the Liferay APIs and frameworks I'm going to cover are really combinations of well-documented software design patterns (in fact Liferay source actually implements a large swath of creational, structural and behavioral design patterns in such purity and clarity they are easy to overlook).

These blog posts may not be defining clean and simple design patterns as specified by the Gang of Four, but they will try to live up to the ideals of true design patterns. They will provide general, reusable solutions to commonly occurring problems in the context of a Liferay-based system.

Ultimately the goal is to demonstrate how by applying these Liferay Design Patterns that you too can design and build a Liferay-based solution that is rich in presentation, robust in functionality and consistent in usage and display. By providing the motivation for using these APIs and frameworks, you will be able to evaluate how they can be used to take your Liferay projects to the next level.

Pattern: Flexible Entity Presentation

Intent

The intent of the Flexible Entity Presentation pattern is to support a dynamic templating mechanism that supports runtime display generation instead of a classic development-time fixed representation, further separating view management from portlet development.

Also Known As

This pattern is known as and implemented on the Application Display Template (ADT) framework in Liferay.

Motivation

The problem with most portlets is that the code used to present custom entities is handled as a development-time concern; the UI specifications define how the entity is shown on the page and the development team delivers a solution to satisfy the requirements.  Any change to specifications during development results in a change request for the development team, and post development the change represents a new development project to implement presentation changes.

The inflexibility of the presentation impacts time to market, delivery cycles and development resource allocation.

The Flexible Entity Presentation pattern's motivation is to support a user-driven mechanism to present custom entities in a dynamic way.

The users and admins section on ADTs from dev.liferay.com starts:

The application display template (ADT) framework allows Liferay administrators to override the default display templates, removing limitations to the way your site’s content is displayed.

ADTs allow the display of an entity to be handled by a dynamic template instead of handled by static code. Don't get hung up on the word content here, it's not just content as in web content but more of a generic reference to any html content your portlet needs to render.

Liferay identified this motivation when dealing with client requests for product changes to adapt presentation in different ways to satisfy varying client requirements.  Liferay created and uses the ADT framework extensively in many of the OOTB portlets from web content through breadcrumbs.  By leveraging ADTs, Liferay defines the entities, i.e. a Bookmark, but the presentation can be overridden by an administrator and an ADT to show the details according to their requirements, and all without a development change by Liferay or a code customization by the client.

Liferay eats its own dogfood by leveraging the ADT framework, so this is a well tested framework for supporting dynamic presentation of entities.

When you look at many of the core portlets, they now support ADTs to manage their display aspects since tweaking an ADT is much simpler than creating a JSP fragment bundle or new custom portlet or some crazy JS/CSS fu in order to affect a presentation change. This flexibility is key for supporting changes in the Liferay UI without extensive code customizations.

Applicablility

The use of ADTs apply when the presentation of an entity is subject to change. Since admins will use ADTs to manage how to display the entities, the presentation does not need to be finalized before development starts. When the ADT framework is incorporated in the design out of the gate, flexibility in the presentation is baked into the design and doors are open to any future presentation changes without code development, testing and deployment.

So there are some fairly clear use cases to apply ADTs:

  • The presentation of the custom entities is likely to change.
  • The presentation of the custom entities may need to change based upon context (list view, single view, etc.).
  • The presentation is not an aspect in the portlet development.
  • The project is a Liferay Marketplace application and presentation customization is necessary.

Notice the theme here, the change in presentation.

ADTs would either not apply or would be overkill for a static entity presentation, one that doesn't benefit from presentation flexibility.

Participants

The participants in this pattern are:

  • A custom entity.
  • A custom PortletDisplayTemplateHandler.
  • ADT Resource Portlet Permissions.
  • Portlet Configuration for ADT Selection.
  • Portlet View Leveraging ADTs.

The participants work together with the Liferay ADT framework to support a dynamic presentation for the entity. The implementation details for the participants are covered here: https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/implementing-application-display-templates.

Collaboration

The custom entity is defined in the Service Builder layer (normally).

The PortletDisplayTemplateHandler implementation is used to feed meta information about the fields and descriptions of the entity to the ADT framework Template Editor UI. The meta information provided will be generally be very coupled to the custom entity in that changes to the entity will usually result in changes to the PortletDisplayTemplateHandler implementation.

The ADT resource portlet permissions must be enabled for the portlet so administrators will be able to choose the display template and edit display templates for the entity.

The portlet configuration panel is where the administrator will chose between display templates, and the portlet view will leverage Liferay's ADT tag library to inject the rendered template into the portlet view.

Consequences

By moving to an ADT-based presentation of the entity, the template engine (FreeMarker) will be used to render the view.

The template engine will impose a performance cost in supporting the flexible presentation (especially if someone creates a bad template). Implementors should strike a balance between benefitial flexibility and overuse of the ADT framework.

Sample Usage

For practical examples, consider a portal based around a school.  Some common custom entities would be defined for students, rooms, teachers, courses, books, etc.

Consider how often the presentation of the entities may need to change and weigh that against whether the changes are best handled in code or in template.

A course or a teacher entity would likely benefit from the ADT as those entities might need to change the presentation of the course as a brochure-like view needs to change, or the teacher when new additions such as accreditation or course history would change the presentation.

The students and rooms may not benefit from ADTs if the presentation is going to remain fairly static.  These entities might go through future presentation changes but it may be more acceptable to approach those as development projects that are planned and coordinated.

Known Uses

The best known uses come from Liferay itself. The list of OOTB portlets which leverage ADTs are:

  • Asset Publisher
  • Blogs
  • Breadcrumbs
  • Categories Navigation
  • Documents and Media
  • Language Selector
  • Navigation Menu
  • RSS Publisher
  • Site Map
  • Tags Navigation
  • Web Content Display
  • Wiki

This provides many examples for when to use ADTs, the obvious advantage of ADTs (customized displays w/o additional coding) and even hints where ADTs may not work well (i.e. users/orgs control panel, polls, ...).

Conclusion

Well, that's pretty much it for this post. I'd encourage you to go and read the section for styling apps with ADTs as it will help solidify the motivations to incorporate the ADT framework into your design. When you understand how an admin would use ADTs to create a flexible presentation of the Liferay entities, it should help to highlight how you can achieve the same flexibility for your custom assets.

When you're ready to realize these benefits, you can refer to the implementing ADTs page to help with your implementation.

 

David H Nebinger 2017-02-15T14:18:18Z
Categories: CMS, ECM

Now Available: Social Office to Liferay 7 Upgrade

Liferay - Mon, 02/13/2017 - 18:09

I am pleased to announce the Social Office to Liferay 7 upgrade has been released!

Introduction

Liferay Social Office was previously an add-on for Liferay Portal CE 6.2 and earlier.  With the release of Liferay 7, most of these components have been added to Liferay Portal CE and Social Office has been removed from Marketplace.  This means that Social Office no longer requires a separate installation, upgrade and support.

Most of the Social Office to Liferay Portal CE 7.0 upgrade process is completed by the standard Liferay upgrade procedure. There are additional steps that need to be completed after the standard upgrade process is finished in order for Social Office to work with Liferay Portal CE 7.0.

Upgrade Overview

Social Office to Liferay 7 Upgrade - We have provided a series of components, an upgrade tool and upgrade instructions that will aid in upgrading Liferay Social Office installations to Liferay 7. The majority of the upgrade follows the standard Liferay 7 Upgrade Guide.  The Social Office upgrade tool ensures that Social Office is properly upgraded to work with Liferay 7.  Changes to Social Office when upgrading to Liferay 7 is covered below.

Social Office Theme - The Social Office Theme has been removed entirely and the Social Office Upgrade Tool will change over to using the out of the box classic theme.  The idea behind this change it the Social Office theme was never meant to be customized.  Now any custom theme can be used instead of being locked into one theme.  

Social Office Site Templates - Social Office installed a set of Site Templates within Liferay Portal upon installation.  These will be carried forward as a part of the upgrade and will work the same as they did in previous versions of Social Office.  For a fresh installation of Liferay 7  the Site Templates can be recreated and used in a similar fashion.

Customized Liferay Portal Apps - Announcements, Document Library Enhancements, Notifications and Bookmarks had specific customizations for Social Office and these have been merged into Liferay 7.  The Chat application is waiting for changes in Liferay Portal 7.0 CE GA4 and will be released shortly after the release of Liferay Portal 7.0 CE GA4

Social Office specific Apps - Microblogs, Contacts Center and Social Office User Profiles are in Liferay 7 out of the box.  Private Messaging, Event List and WYSIWYG are provided as Marketplace apps (links in documentation. The Tasks application has been removed but the source is still available here and can be upgraded to Liferay 7 if need be.

Social Office UX enhancements - The Social Office Dashboard, Social Office Profile and User bar have been replaced by the Liferay 7 Control Panel and the Go To Menu has been replaced by the My Sites application and can be added to a custom theme in Liferay 7 like in previous versions.

Conclusion

A special thanks goes out to everyone who helped by providing feedback and took the time to help test the tooling and the documentation.

Jamie Sammons 2017-02-13T23:09:30Z
Categories: CMS, ECM
Syndicate content