How to custom page view impression in AEM 6.0? - java

I see in AEM 6.0 that have a built-in component for page view statistic, displayed as impression column in author site admin. But this built-in does not support for filter the top page view in sites and so on. This one is useful for calculate page view for each page. I'm facing the performance problem for calculate top page view with more than thousand of pages. Anyone have a solution for this one ?. Many thanks and appreciate.

While the impression data initially appears tempting, it is not meant for end-user page view analytics. The CQ integrations with SiteCatalyst, etc are meant for real analytics (or 3rd party solutions, such as Google Analytics).
If you consider the author displays impressions, 1+ publish instances would have to "reverse replicate" impression data back to the author, which would get pushed right back to publish instances.
When you consider the Apache Dispatchers serving up cached pages w/o passing the request to the publish instances, you can understand how even your production publish instances don't see all the traffic, either.

You can create a variant of the page with a selector. Something like: statistics.html.jsp in your page node, then:
http://example.com/a.html is the normal page
http://example.com/a.statistics.html is the page that adds the statistics component.

Finding top 10 most viewed page or sorting all page based on their popularity using Impression service provided by CQ is a bit tricky because of following reasons
It might possible that Page Views is in external system and then you
want to import those data as impression in CQ to have more
application context.
you have to aggregate all data across all publish instances.
It's Slow.
To calculate top page view with more than thousand of pages you have three options
Creating your Own Impression service
You can create your own impression service by extending
com.day.crx.statistics.Entry. Then You can do all the optimizations.
Adobe analytics: If you have thousands of pages then go with adobe
analytics. It will give you the top results and other filtering
options through their Rest Service.
Modify the OOTB service implementation.
You don't want to write your own service but wanted to use OOTB service available to you. Only problem with this is, You have multiple publish instance and some how you want to combine all data into one so that you get accurate picture. It kind of tricky to get all data from all publish instance (through reverse replication) and then combine them on author and then push them over again. However you can use one instance to collect all stat data (king of single source of truth and then replicate it back to all instance every day)
Make sure that you enable page view tracking by adding following line
<cq:include script="/libs/foundation/components/page/stats.jsp" />
Then configure all publish instance to point to one DNS using following config (You can always override this under /apps)
/apps/wcm/core/config.publish/com.day.cq.wcm.core.stats.PageViewStatistics
/apps/wcm/core/config.publish/com.day.cq.wcm.core.stats.PageViewStatisticsImpl
make sure that pageviewstatistics.trackingurl is pointing to single domain (You need to create a domain, something like impression.mydomain.com that will be stand alone CQ instance to take all impression request)
Now you have consolidated page impression on one machine
You can easily write a scheduler which will run every night and reverse replicate all data to author instance.
Once it is an author instance you can use replicator service to replicate to all other publish instance
Then you can tweak some code as mentioned in the custom approach to get popular resources.
For read more about the Custom implementation:
Implementations instruction:

Related

How can i get page URL in single-approver-definition.xml in Kaleo workflow in Liferay?

How can i get the page URL in single-approver-definition.xml in the e-mail template that is used to send an e-mail to the content creator once the reviewer approves or rejects the submission. The existing xml is as follows:
<template>
Your submission has been reviewed and the reviewer has applied the following:
${taskComments}.
</template>
I tried ${serviceContext.getAttribute("contentURL")} and it didn't work.
I want to be able to do - Your submission for ${pageURL} has been reviewed and the reviewier has applied the following: \n ${taskComments}.\n
Any suggestions will be appreciated.
I don't get what variable exactly you want to process in your notification. As I can only assume, you are using it for Web Contents and all interesting variables are stored in two places.
Workflow context variables - they are available directly. Few examples like:
${taskComments}
${entryType}
${userId}
${userName}
...
ServiceContext variables - they are available using $serviceContext. Few examples:
$serviceContext.getAttributes().get("version")
$serviceContext.getAttributes().get("articleId")
${serviceContext.getPortalURL()}
...
For all interesting variables check this url https://www.liferay.com/web/igor.beslic/blog/-/blogs/workflow-in-action-kaleo-workflow-context-variables Some could change already, however most of them is working fine for current version.
Content changes might be made on a page, they can also be triggered through Control Panel (or the API for that matter). When you're in a workflow, you typically don't have this context any more - if you find it somehow I'd not rely on it to be there. A workflow is unrelated to the UI and pages.
Also, an article might be submitted on one page, where it might be replaced/removed before it's even approved. In that case the link wouldn't help.
What might work is to check the concept behind "Web Content Display Pages" (if your article has them configured and you deal with web content). But the mechanics will vary depending on the actual content type you're dealing with. And content that goes through workflow might not be displayed on any page at all (e.g. when submitted through Control Panel) or on many different pages (either explicitly - Web Content Display - or implicitly - Asset Publisher).
#tomic basically provides pointers to what you have, I'm only reasoning why your initial problem is problematic to solve at best - it's not fully specifiable.

JSP/Spring MVC application

I am writing a web application using JSP/Spring MVC and would need to customize the UI based on the customer using it. I would need to hide/show certain sections of the screen, hide show certain labels and their text boxes and also modify labels based on different customers. Currently we are controlling the hide/show in the JSPs by elements and divs based on the logged in customer. For example:
if (customer= "A")
show this
else
hide this
The code gets cluttered and the JSP will get bloated as we add more customers.
Another alternative I have thought is split a page into sections and control the sections in the same way, but might end up in code repetition accross the JSPs.
For example
if (customer = "A")
jsp:include headerA.jsp
else
jsp:include genericheader.jsp
Another alternative would be to write different JSPs and route based on the client.
Is there a better way to handle this kind of situations. Can someone suggest the best practices to implement such a solution?
Thanks.
A UI that chooses what to do for each user can't possibly scale beyond your users A and B. You need a role-based authentication and authorization system.
Since you're already using Spring, I'd recommend looking at Spring Security and its role based capabilities. There are tags that can help you.
Another way to look at it is that role-based logic like this does not belong in tags. I'd recommend putting it in controllers and let them assemble pages for you.
Another possibility is something like SiteMesh, which allows you to create composite views.
One more: jQuery was born to manipulate the DOM. Use it along with CSS.
First thing it should be based on Role and not based on customer, and each customer will have certain role. It may possible that many customers will have same role and screen access and UI.
Based on role, you can use Spring Secutiry for Authentication and Authorization.
If you need to use Layout differently as per customer role, preferably you should use some Layout Manager such as Tiles, SiteMesh etc.
or use portlets for different login views to different customers
You just stated if person A logs in from one store, vs person B logs in from another. Hate to say it, but that's a role, no matter how you want to spin it, this is related to user authorization.
In terms of how you want to implement it, you could do a variety of things, you could intercept the login request and set a session variable which prepends a string to determine the correct view (i.e. when user a logs in you get customerA, vs customerB, so when rendering the view you'd retrieve the value and render "customerA/index" vs. "customerB/index", etc.
You could also determine the person's roles within the controller and render the appropriate view, although this couples your user roles to your controller logic, which wouldn't be recommended in my opinion.
If this app is going to have a lot of different backends, I'd recommend portlets that way you can write a new backend for each app, rather than bloating your web application with every new store backend.
Those are just a couple ways, hope this helps.

Decorating a multi-client webapp

I have a web-app in Java, Spring, Struts 2 and Hibernate, that servers multiple clients. Each client with multiple users. To create a personal feel for each client, i would like to customize the header for each client.
I'm using sitemesh as decorator, and am looking for tips or examples or someone who can point me in the right direction as to how to acomplish this in the best practice.
What would you think? Should i just code it direct in the header.jsp? Extracting the info about the logged in user and from that create a custom header by code? Or is there a more clever solution out there?
Thanks!
Update:
To further clearify what i want:
Different properties-files for each client is not an option. We are looking at potentionally hundreds of clients. It needs to be database-driven. But thats the easy part. There is no problem storing the information in db and extracting it when needed.
What im trying to figure out is if there is some sort of standard way of doing this. Some sort of filter or Action that is run before the sitemesh decorator that will provide the decorator with the correct info?
Struts2 provides application scope, for variables which are global to the application.
Load all the customer specific strings into #application scope (I would use spring to do this when the application starts up). From there referencing the strings would be pretty obvious: #application.greeting I don't like the idea of using an interceptor because there is nothing to intercept. I would say for what you are doing application scope is the perfect place. If it is a single client system I can see no reason why anything would be stored in application scope.
Aside: Tiles uses a different template paradigm than site mesh, and they have slightly different purposes. As such the two can be complimentary. Tiles relying on XML definitions can have it's definitions stored in a DB and is definitely less computationally intensive, however where there is interplay between different UI components... or disparate elements appearing on the page you need to use sitemesh. So for basic template needs tiles does everything and is quite easy to understand but say you wanted to make add a certain widget in the middle of the page which relies on JS which needs to be added to the header it would be tricky to do this in Tiles (although the obvious solution is to just roll the JS functionality into one JS file for all possible uses in a particular part of the site).
Asside 2: By using a view technology such as velocity or freemarker in conjunction with tiles it is conceivable to move the entire view layer into a database. I just thought I would mention that as for some maintenance issues that could be extremely beneficial.
Sitemesh makes it's decisions about what decoration to use based upon the requested URL string, so unless you have a reference to the client in every url - either as part of the main url string or as a known parameter, then Sitemesh out of the box is not going to help.
This leaves a few possibilities to achieve what you want;
1) Write a filter that runs before Sitemesh that adds, for example, "&clientId="xx" to every incoming request.
2) Dive into the source code for Sitemesh & look for where Sitemesh finally makes it's decision about which decorators to use and override it. I've never tried this so I don't know how practical this might be.
3) Make the style sheet definition in your jsp pages an OGNL expression and provide that information in a base action class that all your actions extend. In this way you end up with (potentially) a different CSS file for each client and you provide your customisation via CSS.
Hope that this helps.

Multipage environment in GWT

I have been developing an AJAX web application using GWT. I've read several blogs and forums about this question and left with no clear idea. I understand that GWT is an AJAX application, that supports only stand-alone web application. By stand-alone, I meant GWT to be a single web page that would suffice the user requirements. However the use case I have is pretty complex and I'm stuck in this use case that doesn't let me proceed.
My usecase(s) goes like this:
Usecase #1: There is an order entry form where user will enter a search string to search for a particular item. With GWT, I could display the result in a table (say celltable). However, when I click a column in the cellTable, I want the value of the column to be sent to the server and display another page that will display only the details of the selected column. I'm not sure how to accomplish this.
Usecase #2: Let's say the web application I develop is called "InventoryControl" and I have different requirements such as:
display Available stock
display Order stock
display Manufactured unit
and Using Java servlets, I could just type http://localhost/availableStock?stockId=1234 on my browser to get the "Display available stock" for the given stockId and then http://localhost:orderStock?stockId=1234 to get the "display order stock" and similarly "display manufactured unit". Is the same possible using GWT? i.e. when I type http://localhost/availableStock?stockId=1234, is it possible to read the parameter being passed and then display the corresponding page?
If these are not meant to be guaranteed by GWT, should I stick with Plain old JAVA servlets/JSP?
Thanks in advance.
Ashok - Please note, what filip suggests above does not require multiple "pages" in the sense of additional html host pages. You can build a panel holding your display of the details, and swap it into the rootpanel of your host in the onSuccess() of your rpc call. The GWT history mechanism allows you to assign anchors to these "places" and provide a mechanism to map these anchors to specific display classes in your code.
GWT already has a mechanism for handling multiple page applications. Have a look at Activities and Places. You can define each page as a place in your application, and use the GWT mechanism to go from place to place at any time. Using places also allows you to easily add tokens/query parameters to each "page", in an OO manner, without having to worry about populating/querying the URL directly. Have a good read of the link!

Managing webapp session data/controller flow for multiple tabs

I have a Java web application which stores some data in the session. The data in the session changes as the user interacts with the application (e.g. flow is managed by a controller, each controller has several form pages, on each form page some data is updated in the session and flow goes to the next form page).
The problem is that some users are opening more than one tab to the application, each tab with a different step in the flow. At this point data in the session is messed up since the tabs share the same session (app uses cookie managed sessions).
Telling the users to use different browsers to avoid sharing the same session id (e.g. one Firefox window and one IE window) is not an option since surely at some point somebody will forget to do this and instead use tabs, thus messing up their data.
Adding some verifications that detect that another flow is requested from another tab and display a message to the user saying this is not allowed is not an option either since it pisses of the users and we don't want that do we? :D
The fact is that using another tab is useful for the users because they are more efficient in what they use the application for, so I am keeping this option. But the question now is how best to manage the one session data for the more tabs?
What I thought of, was to have the controller generate a token when it starts the flow and pass this token to each form page which in turn sends it back to identify itself. If another tab requests the same controller action when there is an ongoing flow then generate another token and pass that around.
Basically, I want each flow to have a token and inside the session I won't just keep one set of data but have a set of data for each token and then match requests based on the token.
Now the problem is that this approach will need a lot of rewritings to the application and I was wondering if there is a best practice for managing such a situation or can someone suggest other approaches. I am open to ideas.
Have you encountered this situation? How did you handle it?
This is usually done by assigning a windowId for each tab/window and passing it on each request. Jsf supports this via orchestra. Spring mvc will support it in the next version.
I recently needed this for a simple case, so I implemented it myself. Took half an hour. However, my scope was very limited:
pass a windowId with each request, and return it back for the next request. The first time - generate it.
for any attribute you want to store in the session, put a Map<String, Object> where the key is the windowId
This is exactly what Seam was created to handle. In Seam there's a concept called a Conversation which basically does exactly what you are explaining. Conversations are basically are a way to divide the Session into many pieces that can expire at some timeout. You can look at the source code for org.jboss.seam.core.Manager class to see how it's actually implemented and get inspired ;)
Depending on the complexity of your application, you may want to investigate implementing tabs within your application. This gives you wholesale control over the flow, while still providing users with the functionality they want. I'd argue it's, bugwise, the most robust solution, since you won't have a dependency on the way the browser handles sessions, minimising the number of "known unknowns".
Of course, there'll be potentially a large upfront cost to this, depending on how your application is structured. Without more information about your app, you're the best placed person to decide.
You can also try to wrap your application inside Adobe Air
And then limit your web application to be only accessable from this air. By doing this you dont need to consider the web browser fragmentation and their unique behaviour.

Categories