|
package sample.wcm.query.portlet; |
|
|
|
import java.io.IOException; |
|
import java.util.ArrayList; |
|
import java.util.Arrays; |
|
import java.util.List; |
|
|
|
import javax.portlet.GenericPortlet; |
|
import javax.portlet.PortletException; |
|
import javax.portlet.PortletRequestDispatcher; |
|
import javax.portlet.RenderRequest; |
|
import javax.portlet.RenderResponse; |
|
import javax.portlet.ResourceRequest; |
|
import javax.portlet.ResourceResponse; |
|
|
|
import org.apache.commons.lang.StringUtils; |
|
|
|
import com.ibm.workplace.wcm.api.Category; |
|
import com.ibm.workplace.wcm.api.Content; |
|
import com.ibm.workplace.wcm.api.ContentComponent; |
|
import com.ibm.workplace.wcm.api.DocumentId; |
|
import com.ibm.workplace.wcm.api.DocumentLibrary; |
|
import com.ibm.workplace.wcm.api.FileComponent; |
|
import com.ibm.workplace.wcm.api.ImageComponent; |
|
import com.ibm.workplace.wcm.api.Repository; |
|
import com.ibm.workplace.wcm.api.TextComponent; |
|
import com.ibm.workplace.wcm.api.WCM_API; |
|
import com.ibm.workplace.wcm.api.Workspace; |
|
import com.ibm.workplace.wcm.api.exceptions.ComponentNotFoundException; |
|
import com.ibm.workplace.wcm.api.exceptions.OperationFailedException; |
|
import com.ibm.workplace.wcm.api.exceptions.QueryServiceException; |
|
import com.ibm.workplace.wcm.api.exceptions.ServiceNotAvailableException; |
|
import com.ibm.workplace.wcm.api.query.Disjunction; |
|
import com.ibm.workplace.wcm.api.query.ProfileSelectors; |
|
import com.ibm.workplace.wcm.api.query.ResultIterator; |
|
import com.ibm.workplace.wcm.api.query.Selectors; |
|
|
|
/** |
|
* A portlet that demos accessing content items with the Query API and doing filtering on Elements. |
|
* @author RBester |
|
* |
|
*/ |
|
public class WcmQueryExamplePortlet extends GenericPortlet { |
|
|
|
private static final String DOCUMENT_LIBRARY = "java-api-test-library"; |
|
private static final String NATIONAL_ID_ELEMENT_NAME = "nationalID"; |
|
|
|
@Override |
|
public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException, IOException { |
|
super.serveResource(request, response); |
|
|
|
// comma-delimited list of content item names, category names, keywords and a custom element. |
|
String contentNames = request.getParameter("contentNames"); |
|
String categoryNames = request.getParameter("categoryNames"); |
|
String keywords = request.getParameter("keywords"); |
|
String nationalIds = request.getParameter("nationalIds"); |
|
|
|
//Retrieve the workspace |
|
Workspace workspace = null; |
|
Repository repository = WCM_API.getRepository(); |
|
try { |
|
// Use the logged-in user credentials to log in to the workspace |
|
workspace = repository.getWorkspace(request.getUserPrincipal()); |
|
workspace.login(); |
|
|
|
// use a specific WCM library that is available on the Virtual portal |
|
DocumentLibrary library = workspace.getDocumentLibrary(DOCUMENT_LIBRARY); |
|
|
|
com.ibm.workplace.wcm.api.query.Query query = workspace.getQueryService().createQuery(); |
|
|
|
/* |
|
* Select all content items for a specific library, with either categories, keywords or names as requested. |
|
* Use a Disjunction (OR) compound selector to add the relevant Selectors to (categories OR keywords OR names) |
|
*/ |
|
Disjunction or = addOrClauses(workspace, library, categoryNames, keywords, contentNames); |
|
|
|
// limit to the library and Content, with the specified OR clause. |
|
query.addSelector(Selectors.libraryEquals(library)); |
|
query.addSelector(Selectors.typeIn(Content.class)); |
|
query.addSelector(or); |
|
|
|
// We're interested in the objects themselves (Document) and not the IDs (DocumentId) |
|
query.returnObjects(); |
|
|
|
/* |
|
* Filter the results on the provided custom element (TextElement) value. |
|
* We need to filter, as there isn't a facility in the Query API to search on Document Elements. |
|
*/ |
|
ResultIterator resultIterator = workspace.getQueryService().execute(query); |
|
List<Content> content = packageContentInList(resultIterator); |
|
|
|
// apply filter |
|
content = filterByNationalId(content, nationalIds); |
|
|
|
// print the results as HTML by traversing the Content Elements (previously known as ContentComponent and still that name in the API) |
|
response.getWriter().write(generateDocumentList(content)); |
|
|
|
} catch (ServiceNotAvailableException e) { |
|
e.printStackTrace(); |
|
} catch (OperationFailedException e) { |
|
e.printStackTrace(); |
|
} catch (QueryServiceException e) { |
|
e.printStackTrace(); |
|
} finally { |
|
if (workspace != null) { |
|
workspace.logout(); |
|
} |
|
if (repository != null) { |
|
repository.endWorkspace(); |
|
} |
|
} |
|
} |
|
|
|
private Disjunction addOrClauses(Workspace workspace, DocumentLibrary library, String categoryNames, String keywords, String contentNames) { |
|
Disjunction or = new Disjunction(); |
|
addCategoriesSelectors(workspace, library, or, categoryNames); |
|
addKeywordSelectors(or, keywords); |
|
addNamesSelectors(or, contentNames); |
|
return or; |
|
} |
|
|
|
private void addCategoriesSelectors(Workspace workspace, DocumentLibrary library, Disjunction or, String categoryNames) { |
|
if (StringUtils.isEmpty(categoryNames)) { |
|
return; |
|
} |
|
|
|
try { |
|
List<DocumentId> categories = findCategories(workspace, library, categoryNames); |
|
or.add(ProfileSelectors.categoriesContains(categories)); |
|
} catch (QueryServiceException e) { |
|
e.printStackTrace(); |
|
} |
|
} |
|
|
|
private void addKeywordSelectors(Disjunction or, String keywords) { |
|
if (StringUtils.isEmpty(keywords)) { |
|
return; |
|
} |
|
|
|
or.add(ProfileSelectors.keywordsContain(splitKeywords(keywords))); |
|
} |
|
|
|
private void addNamesSelectors(Disjunction or, String itemNames) { |
|
if (StringUtils.isEmpty(itemNames)) { |
|
return; |
|
} |
|
|
|
or.add(Selectors.nameIn(splitKeywords(itemNames))); |
|
} |
|
|
|
/* |
|
* Loops through the content items and interrogates the ContentComponent (Element). If it's a TextElement (which it should be), |
|
* the text should match our search criteria. |
|
*/ |
|
private List<Content> filterByNationalId(List<Content> contentItems, String nationalIds) { |
|
if (StringUtils.isEmpty(nationalIds)) { |
|
return contentItems; |
|
} |
|
|
|
List<Content> toReturn = new ArrayList<Content>(); |
|
for (Content contentItem: contentItems) { |
|
try { |
|
ContentComponent contentComponent = contentItem.getComponent(NATIONAL_ID_ELEMENT_NAME); |
|
if (containsContentText(nationalIds, contentComponent)) { |
|
toReturn.add(contentItem); |
|
} |
|
} catch (ComponentNotFoundException e) { |
|
System.out.println("component not found: " + e.getMessage()); |
|
} |
|
} |
|
return toReturn; |
|
} |
|
|
|
/* |
|
* Match TextComponent's text with a comma-delimited list of search terms |
|
*/ |
|
private boolean containsContentText(String textToScan, ContentComponent contentComponent) { |
|
if (contentComponent instanceof com.ibm.workplace.wcm.api.TextComponent) { |
|
String componentText = ((com.ibm.workplace.wcm.api.TextComponent) contentComponent).getText(); |
|
return textToScan.contains(componentText); |
|
} |
|
return false; |
|
} |
|
|
|
/* |
|
* Casts and adds results to a List for convenience. |
|
*/ |
|
private List<Content> packageContentInList(ResultIterator resultIterator) { |
|
List<Content> toReturn = new ArrayList<Content>(); |
|
Object nextItem; |
|
while(resultIterator.hasNext()) { |
|
nextItem = resultIterator.next(); |
|
if (nextItem instanceof Content) { |
|
toReturn.add((Content)resultIterator.next()); |
|
} |
|
} |
|
return toReturn; |
|
} |
|
|
|
/* |
|
* Generate HTML to be printed |
|
*/ |
|
private String generateDocumentList(List<Content> content) { |
|
StringBuilder documentHtml = new StringBuilder(); |
|
for (Content contentItem : content) { |
|
documentHtml.append(getContentDescription(contentItem)); |
|
} |
|
|
|
return documentHtml.toString(); |
|
} |
|
|
|
/* |
|
* Tokenize the keywords/search terms |
|
*/ |
|
private List<String> splitKeywords(String keywords) { |
|
String [] splitKeywords = keywords.split(","); |
|
return Arrays.asList(splitKeywords); |
|
} |
|
|
|
/* |
|
* To search by categories, we need to first fetch all the categories' IDs, then use those in the query. |
|
* Typically one could cache the categories so this lookup isn't needed all the time. |
|
*/ |
|
private List<DocumentId> findCategories(Workspace workspace, DocumentLibrary library, String categories) throws QueryServiceException { |
|
String[] categoriesSplit = categories.split(","); |
|
com.ibm.workplace.wcm.api.query.Query query = workspace.getQueryService().createQuery(); |
|
query.addSelector(Selectors.typeIn(new Class[] {Category.class})); |
|
query.addSelector(Selectors.libraryEquals(library)); |
|
query.addSelector(Selectors.nameIn(categoriesSplit)); |
|
query.returnIds(); |
|
ResultIterator resultIterator = workspace.getQueryService().execute(query); |
|
List<DocumentId> toReturn = new ArrayList<DocumentId>(); |
|
|
|
while (resultIterator.hasNext()) { |
|
toReturn.add((DocumentId) resultIterator.next()); |
|
} |
|
|
|
return toReturn; |
|
} |
|
|
|
/* |
|
* Returns html for ContentItem with text, an ImageComponent/Element and a FileComponent (e.g. pdf). |
|
*/ |
|
private String getContentDescription(Content content){ |
|
String result = ""; |
|
try { |
|
String[] componentNames = content.getComponentNames(); |
|
for(int i = 0; componentNames != null && i < componentNames.length; i++){ |
|
ContentComponent contentComponent = content.getComponent(componentNames[i]); |
|
if(contentComponent instanceof TextComponent){ |
|
result += componentNames[i] + ": " + ((TextComponent)contentComponent).getText() + "<br>"; |
|
} else if(contentComponent instanceof ImageComponent){ |
|
result += componentNames[i] + ": <a href='" + ((ImageComponent)contentComponent).getResourceURL() + "'>Image</a><br>"; |
|
} else if(contentComponent instanceof FileComponent){ |
|
result += componentNames[i] + ": <a href='" + ((FileComponent)contentComponent).getResourceURL() + "'>File</a><br>"; |
|
} |
|
} |
|
result += "<br>"; |
|
} catch(ComponentNotFoundException e){ |
|
e.printStackTrace(); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
@Override |
|
protected void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { |
|
PortletRequestDispatcher dispatcher = getPortletConfig().getPortletContext().getRequestDispatcher("/WEB-INF/jsp/WcmQueryUtilitiesPortlet.jsp"); |
|
dispatcher.forward(request, response); |
|
} |
|
|
|
} |