Forums

Home » Liferay Portal » English » 3. Development

Combination View Flat View Tree View
Threads [ Previous | Next ]
toggle
Roger Wilson
Programatically pulling Web Content
February 20, 2013 8:13 AM
Answer

Roger Wilson

Rank: Junior Member

Posts: 29

Join Date: February 20, 2013

Recent Posts

Hi,

I'm relatively new to Liferay's Java API and I'm trying to pull information for Related Assets. Client has requested the ability to preview information prior to publishing. In this case, we're working with JournalArticle objects.

We've set up a page for them to view their main content as-written in CKEditor to display regardless of display date. This resolved their issues as far as main content, but our related asset widgets will only display information that is up-to-date with the most recent publish. It WILL pull from a draft if no publish has taken place, but once a publish has gone through, we're locked into that view until the next publish.

Programatically, it seems to stem from the following code we've written (not myself, but another developer):

// Get some context
String layoutUuid = themeDisplay.getLayout().getUuid();
long groupId = themeDisplay.getScopeGroupId();

//...

// Find the Journal Article associated with this page
List<JournalArticle> articles = null;
try {
articles = JournalArticleServiceUtil.getArticlesByLayoutUuid(groupId, layoutUuid);
} catch(Exception e) {

}
long articleId = 0;

// We we get a hit then make this the article,
if (articles != null && articles.size() > 0) {
articleId = articles.get(0).getResourcePrimKey();
} else {
Long sessionArticleId = (Long) renderRequest.getPortletSession().getAttribute("articleResourceId", PortletSession.APPLICATION_SCOPE);
if (sessionArticleId != null) {
articleId = sessionArticleId;
}
}

JournalArticle article = null;
if (articleId > 0) {
try {
// Find the latest published version of the Journal Article and its asset links
article = JournalArticleServiceUtil.getLatestArticle(articleId);
} catch (Exception e) {

}
}

if (article != null) {
AssetEntry assetEntry = AssetEntryLocalServiceUtil.getEntry(JournalArticle.class.getName(), article.getResourcePrimKey());
List<AssetLink> assetLinks = AssetLinkLocalServiceUtil.getDirectLinks(assetEntry.getPrimaryKey());

// Iterate links
for(AssetLink assetLink : assetLinks) {
//...
}
}


I've posted a little more code than is probably necessary, but the core of it seems to come from that when we grab from this line:

article = JournalArticleServiceUtil.getLatestArticle(articleId);

We're only able to get the article object as described: it's always the most recently published article. This bears out in the "assetLink" for loop: it's only seeing the related assets based on the most recent publish.

So here's the REAL problem: after drilling down this far, I'm not finding any overloads for "getLatestArticle" that seem to get what I'm looking for, either under the "JournalArticleServiceUtil" or "JournalArticleLocalServiceUtil" objects (What is the semantic difference between these objects, btw?). I know this has been stated before, but the bare documentation doesn't quite make it clear how these differ or what their parameters might give us:

1. JournalArticleLocalServiceUtil.getLatestArticle(long resourcePrimKey, int status)
(resourcePrimKey we're using in the above call, but what's status? Is it an enumeration? Does it have any bearing on if a given article is in Draft or not?)

2. JournalArticleLocalServiceUtil.getLatestArticle(long resourcePrimKey, int status, boolean preferApproved)
(same as above, but does the boolean preferApproved have any bearing?)

3. JournalArticleLocalServiceUtil.getLatestArticle(long groupId, String articleId, int status)
(This actually doesn't pull the content when I insert some calls to get the articleId [this should not be confused with the articleId in the above code, which is really the resourcePrimKey]. But maybe this would be of theoretical help?)

4. JournalArticleLocalServiceUtil.getLatestArticle(long groupId, String className, long classPK)

The below are similar, but using JournalArticleServiceUtil rather than JournalArticleLocalServiceUtil:

5. JournalArticleServiceUtil.getLatestArticle(long groupId, String articleId, int status)

6. JournalArticleServiceUtil.getLatestArticle(long resourcePrimKey)

7. JournalArticleServiceUtil.getLatestArticle(long groupId, String className, long classPK)

Any help on this would be greatly appreciated.
Chintan Akhani
RE: Programatically pulling Web Content
February 21, 2013 9:24 AM
Answer

Chintan Akhani

Rank: Regular Member

Posts: 111

Join Date: March 13, 2008

Recent Posts

1. JournalArticleLocalServiceUtil.getLatestArticle(long resourcePrimKey, int status)
(resourcePrimKey we're using in the above call, but what's status? Is it an enumeration? Does it have any bearing on if a given article is in Draft or not?)

"It's web content's status, whether you are looking for 'draft' , 'expired' or 'published' content, for appropriate values, have a look at WorkflowConstant.java"

2. JournalArticleLocalServiceUtil.getLatestArticle(long resourcePrimKey, int status, boolean preferApproved)
(same as above, but does the boolean preferApproved have any bearing?) -

"I have not used this method but as per the signature it looks like if 'preferApproved' is true than it will only search for published articles."

3. JournalArticleLocalServiceUtil.getLatestArticle(long groupId, String articleId, int status)
(This actually doesn't pull the content when I insert some calls to get the articleId [this should not be confused with the articleId in the above code, which is really the resourcePrimKey]. But maybe this would be of theoretical help?)

"Here you have to pass articleId not resourcePrimKey. Whenever you create an article it creates 2 entries, one is in journalArticle table and another one is in 'assetEntry'. Here resourcePrimKey is mapped to 'classPK' of assetEntry."

4. JournalArticleLocalServiceUtil.getLatestArticle(long groupId, String className, long classPK)

The below are similar, but using JournalArticleServiceUtil rather than JournalArticleLocalServiceUtil:

"Liferay provides two types of services, one is 'local' and another one is 'remote'". Check the 'remote service implementation', first it checks for permission and than it calls local service , so here permission check is the only diff."

5. JournalArticleServiceUtil.getLatestArticle(long groupId, String articleId, int status)

6. JournalArticleServiceUtil.getLatestArticle(long resourcePrimKey)

7. JournalArticleServiceUtil.getLatestArticle(long groupId, String className, long classPK)
Roger Wilson
RE: Programatically pulling Web Content
February 22, 2013 8:47 AM
Answer

Roger Wilson

Rank: Junior Member

Posts: 29

Join Date: February 20, 2013

Recent Posts

Hi Chintan, thanks so much for your response.

I finally did find the "WorkflowConstants" object, and attempted to use every variation that could fit as a parameter (some of the static elements are strings, but many are integers). However none of them seemed to work. At best they gave me the article of the most recently published version, or worse, nothing at all -- even when trying "STATUS_DRAFT" or "STATUS_ALL" or "ACTION_SAVE_DRAFT" (the last not being a status, I know, but I was getting a bit desperate). The value of the 'preferApproved' boolean doesn't seem to make any difference either.

This has made me ponder if the problem is so much that I'm getting the wrong article object, but if I'm calling the wrong method versions to pull the assetEntry, or the list of related assets from that entry. Unfortunately there doesn't seem to be many options available in that department that I can see. As noted in the code, We're using something that looks generally like:


article = JournalArticleServiceUtil.getLatestArticle(articleId);

if (article != null) {
AssetEntry assetEntry = AssetEntryLocalServiceUtil.getEntry(JournalArticle.class.getName(), article.getResourcePrimKey());
List<AssetLink> assetLinks = AssetLinkLocalServiceUtil.getDirectLinks(assetEntry.getPrimaryKey());

// Iterate links
for(AssetLink assetLink : assetLinks) {
//...
}
}


I'm constantly getting the same values in that assetLinks collection, but there should definitely be more entries in a newest draft (unpublished), since you can see them in the back end. I've tried versions of .getLinks and ..getDirectLinks in case those lists themselves were versioned or something, but there's been no dice so far. There's got to be a way...
Chintan Akhani
RE: Programatically pulling Web Content
February 22, 2013 11:54 AM
Answer

Chintan Akhani

Rank: Regular Member

Posts: 111

Join Date: March 13, 2008

Recent Posts

Roger Wilson:

article = JournalArticleServiceUtil.getLatestArticle(articleId);


This method will give you an article of latest version only. If you want to get all versions than there are two ways to achieve it.

1. Use dynamic query.
2. Use boolean query (lucene search), but this option will be only applicable to published content search, as draft and expired contents are not searhable using lucene.

For what purpose you are using assetLink?
Roger Wilson
RE: Programatically pulling Web Content
April 4, 2013 1:34 PM
Answer

Roger Wilson

Rank: Junior Member

Posts: 29

Join Date: February 20, 2013

Recent Posts

Hi, sorry for the long delay in replying.

I am creating a portlet that displays assetLinks, and will decide when or when not to display them in particular contexts. That context for the moment being when the related asset link has been removed from the list, do not show it.

This is easy enough to accomplish if you have removed the related asset and then published the change, but if you merely save it to draft, the collection seems to be unchanged for each article grabbed from the articleId.

I took your advice and tried a dynamic query using the following line:

DynamicQuery tempQuery = DynamicQueryFactoryUtil.forClass(JournalArticle.class).add(PropertyFactoryUtil.forName("resourcePrimKey").eq(currentArticleId));

Where "currentArticleId" is actually the resource primary key, pulled off of articleDisplay.getResourcePrimKey() -- and in this case the articleDisplay in question is actually showing me the most current content, even if it has been saved to draft rather than published.

So, I'm getting the resource key off of the proper articleDisplay, and I'm executing a dynamic query off of that where the only criteria given is that key. But when I loop through those articles, each one only matches the most recent publish. It will only match the most recent draft save if the content in question has not been previously published.
Chintan Akhani
RE: Programatically pulling Web Content
April 10, 2013 12:15 PM
Answer

Chintan Akhani

Rank: Regular Member

Posts: 111

Join Date: March 13, 2008

Recent Posts

Roger Wilson:
Hi, sorry for the long delay in replying.

So, I'm getting the resource key off of the proper articleDisplay, and I'm executing a dynamic query off of that where the only criteria given is that key. But when I loop through those articles, each one only matches the most recent publish. It will only match the most recent draft save if the content in question has not been previously published.


I am not getting above quoted details, can you please explain it. Let me tell you one thing, if you are looking for draft content than pass one more property into dynamic query for 'status' as well, if it is not the case than please reply back with more details.
Roger Wilson
RE: Programatically pulling Web Content
April 11, 2013 2:17 PM
Answer

Roger Wilson

Rank: Junior Member

Posts: 29

Join Date: February 20, 2013

Recent Posts

Chintan Akhani:
Roger Wilson:
Hi, sorry for the long delay in replying.

So, I'm getting the resource key off of the proper articleDisplay, and I'm executing a dynamic query off of that where the only criteria given is that key. But when I loop through those articles, each one only matches the most recent publish. It will only match the most recent draft save if the content in question has not been previously published.


I am not getting above quoted details, can you please explain it. Let me tell you one thing, if you are looking for draft content than pass one more property into dynamic query for 'status' as well, if it is not the case than please reply back with more details.


Sure, thanks again.

There's been some developments as I've attacked this problem, but the issue remains this: accessing the most recent 'list' of related assets.

In order to access this list, my first order of business is to get the JournalArticle. After some work, I'm confident that I can find the right JournalArticle. Assuming we have the right Id, I can get this by a few means, but one of them is the DynamicQuery mentioned above, where articleId is the id in question:

DynamicQuery newQuery1 = DynamicQueryFactoryUtil.forClass(JournalArticle.class).add(PropertyFactoryUtil.forName("resourcePrimKey").eq(articleId);
List<JournalArticle> list = JournalArticleServiceUtil.dynamicQuery(newQuery1);


This gets me a list of all versions of my article. The last one in this list will be a draft, since this is what was last saved. This works: if my last version was, say, 1.6 and is in draft status, then the last JournalArticle I loop through in the collection will have the 1.6 version number and return "true" from the JournalArticle.isDraft() call.

The problem now is that I have to correctly access the related assets as they exist for that particular version of the JournalArticle. Let's say my previous version, 1.5 had been published with a list of 3 related assets. I then removed one of those related assets, and clicked "save as draft". I now have to find that list with only the two remaining related assets, the most up-to-date "version" of the list, and get the titles of the links from their ArticleDisplay objects.

The only way I currently know how to do this is to first get the assetEntry object for the current JournalArticle through the resourcePrimaryKey as it relates to the "classPK" field, then in turn use its entryId to get a list of assetLink objects by doing a search on their "entryId1" fields. THEN, having a given assetLink, I then use its "entryId2" field to get the assetLink's OWN assetEntry object, which I can then grab the proper assetDisplay with a call to AssetDisplayUtil.getAssetDisplay

But as stated, the problem is I'm only ever getting the most recently published version of the list. I'll only get a version associated with a draft if it's the very first time it's saved. Every time after a publish, I have to publish again in order to get it. What's more, this seems to be the same way for all the versions.




For instance, using your DynamicQuery suggestion all the way through, I'll use the following to get the assetEntry objects of the journalArticle (assuming we're working from the correct version, 1.6 in this case, held in tempArticle):

DynamicQuery newQuery2 = DynamicQueryFactoryUtil.forClass(AssetEntry.class).add(PropertyFactoryUtil.forName("classPK").eq(tempArticle.getResourcePrimKey());
List<AssetEntry> list2 = AssetEntryLocalServiceUtil.dynamicQuery(newQuery2);


Then from there we grab the assetLinks, assuming we put the assetEntry into tempAssetEntry1...

DynamicQuery newQuery3 = DynamicQueryFactoryUtil.forClass(AssetLink.class).add(PropertyFactoryUtil.forName("entryId1").eq(tempAssetEntry1.getEntryId());
List<AssetLink> list3 = AssetLinkLocalServiceUtil.dynamicQuery(newQuery3);


This would theoretically give us the list associated with the proper JournalArticle version (but it doesn't. It only gets the most recent published version). Then from there we go back to fetch the assetEntry, assuming we put our looped-through links into "tempLink"...

DynamicQuery newQuery4 = DynamicQueryFactoryUtil.forClass(AssetEntry.class).add(PropertyFactoryUtil.forName("entryId").eq(tempLink.getEntryId2());
List<AssetEntry> list4 = AssetEntryLocalServiceUtil.dynamicQuery(newQuery4);


And it's on these that we call for our assetDisplay, assuming we loop through and give each one a designation of "finalEntry", and we already have out theme display ready in an instance called "themeDisplay":

AssetDisplay assetDisplay = AssetDisplayUtils.getAssetDisplay(finalEntry, themeDisplay);


Unfortunately, this does not work.
Roger Wilson
RE: Programatically pulling Web Content
April 12, 2013 12:00 PM
Answer

Roger Wilson

Rank: Junior Member

Posts: 29

Join Date: February 20, 2013

Recent Posts

Thanks for your help: I've resolved this using your DynamicQuery suggestion. I wasn't giving it the proper information previously.

The problem was trying to grab the assetEntry of the given JournalArticle. It was only yielding one assetEntry, and that was for the already published article. Running a dynamic query works, if you give it both the groupId and the layoutUuid, which I should have considered earlier.

Getting the collection list back from this will, if there is an outstanding draft, give you TWO assetEntry object in the list: one for the published version, one for the draft. It even does this if you've gone through multiple versions, so I'm guessing the layoutUuid updated to a new value either on publication, or when first changing existing published content. After using the modified date to make certain which is the newest version, I got the assetLink objects from that as before and things worked like a charm.

Thanks again.