Saturday, 29 November 2014

Modifying WCM Authoring template in Websphere portal

Use-case :-  If you want to show some ui in Authoring Template for example user is filling multiple data. Now approver is trying to approve it you want to show him all data with a extra table containing all consolidation.

Example :- We will create a Authoring template with one text field and a dojo grid. You people can extend it to your use-case.

Step 1 :- Create a Authoring template with two text fields. One will contain dojo data grid and other contains a descriptive message.


Using manage elements create above fields and save it as given below


Step 2 :- Now create jsp and have a dojo grid in it as given below.

<%@page session="false" contentType="text/html" pageEncoding="ISO-8859-1" import="java.util.*,javax.portlet.*,com.poc.customauthoringtemplate.*" %>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>        
<%@taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v6.1/portlet-client-model" prefix="portlet-client-model" %>        

 <link rel="stylesheet"
href="/wps/portal_dojo/v1.7/dijit/themes/tundra/tundra.css"%>
<link rel="stylesheet"
href="/wps/portal_dojo/v1.7/dojox/grid/resources/Grid.css"%>
<link rel="stylesheet"
href="wps/portal_dojo/v1.7/dojox/grid/resources/tundraGrid.css"%>
<style type="text/css">

/*Grid need a explicit width/height by default*/
#grid {
width: 43em;
height: 20em;
}
</style>
<script>
dojo.require("dojox.grid.DataGrid");
dojo.require("dojo.data.ItemFileWriteStore");

dojo.ready(function(){
    /*set up data store*/
    var data = {
      identifier: 'id',
      items: []
    };
    var data_list = [
      { col1: "normal", col2: false, col3: 'But are not followed by two hexadecimal', col4: 29.91},
      { col1: "important", col2: false, col3: 'Because a % sign always indicates', col4: 9.33},
      { col1: "important", col2: false, col3: 'Signs can be selectively', col4: 19.34}
    ];
    var rows = 60;
    for(var i=0, l=data_list.length; i<rows; i++){
      data.items.push(dojo.mixin({ id: i+1 }, data_list[i%l]));
    }
    var store = new dojo.data.ItemFileWriteStore({data: data});

    /*set up layout*/
    var layout = [[
      {'name': 'Column 1', 'field': 'id', 'width': '100px'},
      {'name': 'Column 2', 'field': 'col2', 'width': '100px'},
      {'name': 'Column 3', 'field': 'col3', 'width': '200px'},
              {'name': 'Column 4', 'field': 'col4', 'width': '150px'}
    ]];

    /*create a new grid:*/
    var grid = new dojox.grid.DataGrid({
        id: 'grid',
        store: store,
        structure: layout,
        rowSelector: '20px'},
      document.createElement('div'));

    /*append the new grid to the div*/
    dojo.byId("gridDiv").appendChild(grid.domNode);

    /*Call startup() to render the grid*/
    grid.startup();
});
</script>

<div id="gridDiv"></div>

Step 3 :- Now copy this jsp(CustomAuthoringTemplatePortletView.jsp) and place in three places as given below

1) C:\IBM\WebSphere\wp_profile\installedApps\192Cell\PA_WCM_Authoring_UI.ear\ilwwcm-authoring.war\jsp\html

2) C:\IBM\WebSphere\wp_profile\installedApps\192Cell\PA_WCMLRingPortJSR286.ear\ilwwcm-localrende.war\jsp\html

3) C:\IBM\WebSphere\wp_profile\installedApps\192Cell\wcm.ear\ilwwcm.war\jsp\html


Step4 :- Now go to authoring template default content then text component and click on the icon beside CustomAt


Place the jsp path in it


click ok and then close it


Step 5 :- Now try to create a content with this AT.























Dojo grid will be displayed in the Authoring UI


Note :- You show your customized UI content in this way. Depending of requirement you can hide this grid during draft stage and show it when it moves to next stage. In this case grid will show consolidated data from all fields.



Thursday, 27 November 2014

Extending displaying WCM search results in web content viewer portlet

Prerequisite :- Please refer to all my previous blogs on WCM search.

Overview :- Now we will further refine the search by providing users a option to search against Authoring template or site-area or content. After reading this blog you can use the meta data you want and make a custom search form. When user click on search button this time we will display content using portal theme in same page.

Search Metadata :- Below are the available points using which you can search against web content management.
Name – the name field of the content
Title – the title field of the object
Descr – the description field
Authors – the authors of the object, in the full distinguished name form
Keywords – the keywords of the object
Lastmodifieddate – the last modified date of the document.
AuthoringTemplate – the Title of the authoring template for the object, assuming content
Category – the Titles of the categories associated with the content
Modifier – the last modifier, in full distinguished name format
Owners – the owners of the document, in full distinguished name format
ExpirationDate – expiration date of the document,
EffectiveDate – effective date of the document

Example :- Now we have the attributes to search against WCM. Now how will you submit your required fields to WCM. For this we will use a form have with text fields in it and submit our attributes. Now we will map names of the key fields to search metadata.


The following parameters can be used in a search query in this format:
<input name="search_parameter" />
search_query
Used to search the content of any elements stored in a content item.
search_authoringtemplate
Used to search the authoring template, if available, that was used to create the content item.
search_authors
Used to search the name or names of the authors for the content item, if any are defined.
search_categories
Used to search the categories of the content item if any are defined.
search_description
Used to search the description of the content item.
search_effectivedate
Note: Search by date only works with the format MMM DD YYYY. For example, Sep 20 2006. To change the format, you will need to edit the SearchService.DateFormatString parameter in the SearchService.properties file.
Used to search the effective date of the content item.
search_expirationdate
Note: Search by date only works with the format MMM DD YYYY. For example, Sep 20 2006. To change the format, you will need to edit the SearchService.DateFormatString parameter in the SearchService.properties file.
Used to search the expiration date of the content item.
search_keywords
Used to search the keywords of the content item if any are defined.
search_lastmodifieddate
Note: Search by date only works with the format MMM DD YYYY. For example, Sep 20 2006. To change the format, you will need to edit the SearchService.DateFormatString parameter in the SearchService.properties file.
Used to search the last modified date of the content item.
search_modifier
Used to search the name of the last person to modify the content item.
search_name
Used to search the name of the content item.
search_owners
Used to search the name or names of the owners of the content item, if any are defined.
search_title
Used to search the title of the content item.

So as a simple example. Lets say I want to search for content that includes the term “IBM”, AND is tagged with a category that has a title of “IBM”.

Sample form :-
<form
action='<PathCmpnt type="servlet"/>/pathToLibrary/siteArea/content method="post">
<table>
<tr><td>
Search Query:
<input type="text" name="search_query"/><br>
Search Category:
<input type="text" name="search_categories"/><br>
</td></tr>
<tr><td align="right">
<input type="submit" value="Search"/>
</td></tr>
</table>
</form>

Opening search results in same page:-  To render the search results in same page we need to submit the form to itself. Edit the PT mentioned in previous blog to as given below{Alternate way is to set a page context by selecting receive context from current page in advanced options in edit mode}.



Now search for a text as given below


Now search results are displayed in same page as desired


Customizing table to look good :-  Modify the html code of search component the way you want


Modify Search-result-navigation to remove go to page number and decrease pagination to 3




Final output



Tuesday, 25 November 2014

Displaying WCM search results in web content viewer portlet

Usecase :-  Client has a requirement he want to search for wcm content along with the design library. For this we can ask client to use default search provided by portal. But if client says he want to display search results in completely a customized portlet we cannot achieve this with above approach. We will use wcm search component.

Overview :- We will make a custom forum where you can search in wcm and display search results in custom form.

Step1:- Create a Authoring template "at_search" as given below.


Create 3 component references as given below and click ok


Step 2 :- Create a presentation template as given below and then click on insert element tags and select the authoring template then below content will be autofilled.


Click ok and save it


Step 3 :-  Now create a html component with name "HTML - Adv Search form
 " to render the search results data


Html code :- 
<table>
 <tr>
 <td>Search by type </td>
 <td>
 <form action='[PathCmpnt type="servlet"]/POC_DesignLibrary/Search/Results' method="post">
 <input type="text" name="search_query" />
 <select name="search_authoringtemplate">
 <option value="">Select one ...</option>
 <option value="News">News</option>
 <option value="Products">Products</option>
 <option value="Locations">Locations</option>
 </select>
 <input type="submit" value="Search" />
 </form>
 </td>
 </tr>
 </table>


Click ok and save



Step 4:- Previously we created html for search form. Now we will create search component "Search-Search Results" to display results.


Click on it and fill the details as below


Header :-
[Component name="./search-result-navigation"]
<table>

Result design :-
<tr>
 <td>
 [AttributeResource attributeName="nameLink" separator=","]
 ([AttributeResource attributeName="relevance" separator=","])
 <br>
 [AttributeResource attributeName="summary" separator=","]
</td> 
</tr>

Footer :-
</table>

Separator :-
<tr>
 <td bgcolor="#FFFAA" colspand="2" />
</tr>


Click ok and save it



Step 5 :- We creates search form, displaying search results now we have to provide pagination to support large search results. Now we need to create a paging component "Search-result-navigation
 ".


                   Click on it and enter below details




Click ok and save it



Step6 :- Now create a site area and map Authoring template and presentation template.


Fill the details and map at and pt


Click ok 



Step7 :- Now create a content with name "Results"


 Enter the details of Content by selecting the html component


Enter the details of the content by selecting search-results component


Now enter information content in text filed and click save and close



Step 8 :- Now create a portal page add web content viewer portlet and associate the content to it.


            Now click edit under Content



Output  :- You can search for content etc.. Modify UI based on your requirement


Sunday, 23 November 2014

Integrating additional WCM Search collection with Portal8 search


Step 1 :- Navigate to PortalAdministration->Search Administration->Manage Search


Recap of portal base search concept

   Default Search Collection :- This contains search collections for wcm and portal by default in portal 8


WCM Content Source :- This resource collection will have all information related to wcm content. When we perform any search operation on wcm related things portal uses this search collection.
URL :- http://localhost:10039/wps/seedlist/myserver?SeedlistId=&Source=com.ibm.workplace.wcm.plugins.seedlist.retriever.WCMRetrieverFactory&Action=GetDocuments


Portal Content Source :- This resource collection will have all information related to portal pages any search related to portal will land here
URL :- http://localhost:10039/wps/seedlist/myserver?Action=GetDocuments&Format=atom&Locale=en_US&Range=100&Source=com.ibm.lotus.search.plugins.seedlist.retriever.portal.PortalRetrieverFactory&Start=0




Step 2 :- Go back to step 1 and Click on New Collection to create a search collection


Step 3 :-  Now click ok a new search collection will be created.


Step 4 :- Now click on newly created search collection to create a content source in it


Step 5 :-  Now click on New Content source to create a source for search collection


SeedList url :- http://localhost:10039/wps/seedlist/server?SeedlistId=POC_DesignLibrary/ST_PersonalizationSiteArea=com.ibm.workplace.wcm.plugins.seedlist.retriever.WCMRetrieverFactory&Action=GetDocuments

SeedListId :- libraryName/siteAreaName

Step 6 :- Now start crawling for indexing content



Note :- After crawling is completed you can have users search against your new search collection.

Friday, 21 November 2014

Creating Custom Perge and delete Action in Web Content Managment

Use-case :- When ever a item gets expired or in some times after publish based on some conditions like time factor you want to delete the content.

Step1 :- Create a dynamic web-project and place below plugin.xml in it

<?xml version="1.0" encoding="UTF-8"?>
<plugin id="com.poc.purgeaction.CustomPurgeAction" name="Custom Purge Action Factory" version="1.0.0" provider-name="IBM"> 
<extension-point id= "CustomPurgeFactory" name="CustomPurgeFactory" />
<extension point="com.ibm.workplace.wcm.api.CustomWorkflowActionFactory" id= "CustomPergeAction" >
<provider class= "com.poc.purge.factory.CustomPurgeFactory"/>
</extension>

</plugin>

Step2 :- Now create two classes one implementing CustomWorkflowActionFactory and other is CustomWorkflowAction

CustomPurgeFactory

package com.poc.purge.factory;

import java.util.Locale;

import com.ibm.workplace.wcm.api.Document;
import com.ibm.workplace.wcm.api.custom.CustomWorkflowAction;
import com.ibm.workplace.wcm.api.custom.CustomWorkflowActionFactory;
import com.poc.purgeaction.CustomPurgeAction;

public class CustomPurgeFactory implements CustomWorkflowActionFactory {

public static final String ActionName = "PocPurgeAction";

@Override
public CustomWorkflowAction getAction(String arg0, Document arg1) {
// TODO Auto-generated method stub
return new CustomPurgeAction();
}

@Override
public String getActionDescription(Locale arg0, String arg1) {
// TODO Auto-generated method stub
return ActionName;
}

@Override
public String[] getActionNames() {
// TODO Auto-generated method stub
return new String[]{ActionName};
}

@Override
public String getActionTitle(Locale arg0, String arg1) {
// TODO Auto-generated method stub
return ActionName;
}

@Override
public String getName() {
// TODO Auto-generated method stub
return ActionName;
}

@Override
public String getTitle(Locale arg0) {
// TODO Auto-generated method stub
return ActionName;
}

}

CustomPurgeAction

package com.poc.purgeaction;

import java.util.Date;

import javax.naming.InitialContext;

import com.ibm.workplace.wcm.api.Document;
import com.ibm.workplace.wcm.api.WebContentCustomWorkflowService;
import com.ibm.workplace.wcm.api.custom.CustomWorkflowAction;
import com.ibm.workplace.wcm.api.custom.CustomWorkflowActionResult;
import com.ibm.workplace.wcm.api.custom.Directive;
import com.ibm.workplace.wcm.api.custom.Directives;
import com.ibm.workplace.wcm.api.custom.DeleteDirectiveParams;

public class CustomPurgeAction implements CustomWorkflowAction {

@Override
public CustomWorkflowActionResult execute(Document arg0) {
WebContentCustomWorkflowService wfService = null;
CustomWorkflowActionResult _results = null;
Directive directive = Directives.DELETE;
//Without the following line, it would softly delete the document
((DeleteDirectiveParams)directive.createDirectiveParams()).setPermanentDelete(true);
try {
InitialContext ctx = new InitialContext();
// Retrieve WebContentCustomWorkflowService using JNDI name
wfService = (WebContentCustomWorkflowService) ctx.lookup("portal:service/wcm/WebContentCustomWorkflowService");
_results = wfService.createResult(directive, "Our client document is permanently deleted ");
} catch(Exception e) { e.printStackTrace();
}
return _results;
}

@Override
public Date getExecuteDate(Document arg0) {
// TODO Auto-generated method stub
return DATE_EXECUTE_NOW;
}

}

Step3 :-  Now you apply above custom action to expire stage. So once item is moved to expire stage the content will be deleted by default.

Thursday, 20 November 2014

Working with TextProvider to localize Authoring template labels

When addressing displaying content across multiple languages .We should take care about content being displayed and even the authoring process should also be adjusted to the locale. WCM has two ways in it.
  • TextProvider
  • MLS(Multi-Lingual-Solution)

TextProvider :-  Using text-provider you can localize authoring template labels to your localized values. For example you can change Display title and description of Authoring template.



   Now think you want to change display title based on locale. We need to create a custom text provider and have localized values in property files.

Step1 :- Create a dynamic web application and place below plugin.xml in it.

<?xml version="1.0" encoding="UTF-8"?>

<plugin id="com.poc"
       name="Sample Text Provider"
       version="1.0.0"
       provider-name="IBM">
       
 <extension
    point="com.ibm.workplace.wcm.api.TextProvider"
    id="SampleTextProvider">
    <provider class="com.poc.textProvider.SimpleTextProvider"/>
 </extension>


</plugin>


Step 2 :-  Create your com.poc.textProvider.SimpleTextProvider by extending com.ibm.workplace.wcm.api.TextProvider

package com.poc.textProvider;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Set;

import com.ibm.portal.ListModel;
import com.ibm.portal.ModelException;
import com.ibm.workplace.wcm.api.plugin.textprovider.TextProvider;

public class SimpleTextProvider implements TextProvider{

/** The text provider title */
public static final String PROVIDER_TITLE = "SampleTextProvider";

/** The unique text provider name */
public static final String PROVIDER_NAME = "SampleTextProvider";

/** A brief description of this text provider */
private static final String PROVIDER_DESCRIPTION = "Simple Text provider";

/** Resource bundle name */
private static final String RESOURCE_BUNDLE_NAME = "SimpleBundle";
/** Resource bundle name */
private static final String RESOURCE_BUNDLE_PROPERTIES_NAME = "SimpleBundle_en.properties";

/** Is shown in authiring UI*/
@Override
public boolean isShownInAuthoringUI() {
return true;
}

@Override
public String getDescription(Locale arg0) {

return PROVIDER_DESCRIPTION;
}

/**
* A simple list model holding locales.
*/
protected static class SimpleLocaleListModel<K> implements ListModel<Locale>
{
/** the list of locales of this list model */
final List<Locale> m_localeList = new ArrayList<Locale>();

/**
* Constructs this simple list model holding the given locales.
* @param p_locales
*           the locales of this list model. May be <code>null</code>.
*/
public SimpleLocaleListModel(final Locale[] p_locales)
{
if (p_locales != null)
{
for (int i = 0; i < p_locales.length; ++i)
{
m_localeList.add(p_locales[i]);
}
}
}

@Override
public Iterator<Locale> iterator() throws ModelException
{
return m_localeList.iterator();
}
}

/** a list model that only contains the English and spanish language locale */
private static final ListModel<Locale> ENGLISH_ONLY = new SimpleLocaleListModel<Locale>(new Locale[]{Locale.ENGLISH,Locale.FRENCH});
@Override
public ListModel<Locale> getLocales() {

return ENGLISH_ONLY;
}

@Override
public String getTitle(Locale arg0) {
return PROVIDER_TITLE;
}

     /*This will return the list of keys which we can select later */
@Override
public Collection<String> getProviderKeys() {
Collection<String> keys = null;
try
{
LinkedProperties props = new LinkedProperties();
props.load(getClass().getClassLoader().getResourceAsStream(RESOURCE_BUNDLE_PROPERTIES_NAME));
keys = props.getKeySet();
}
catch (IOException e)
{
// The bundle was not found. Return null.
e.printStackTrace();
}
return keys;
}

@Override
public String getProviderName() {

return PROVIDER_TITLE;
}

@Override
public String getString(String p_key, Locale p_displayLocale) {
String value;
try
{
ResourceBundle bundle = ResourceBundle.getBundle(RESOURCE_BUNDLE_NAME, p_displayLocale);
value = bundle.getString(p_key);
}
catch (MissingResourceException e)
{
// The bundle or key was not found. Return null.
value = null;
}
return value;
}

/** Used to provide the properties in order */
private class LinkedProperties extends Properties {
/** Keys */
private final LinkedHashSet<String> keys = new LinkedHashSet<String>();

/**
* @return An ordered set of keys
*/
public Set<String> getKeySet()
{
return keys;
}
@Override
public Object put(Object key, Object value) {
keys.add((String) key);
return super.put(key, value);
}
}

}



Step3 :-  Now you need to create property files and place your localized files in it.



Step 4 :- Now make a war file and deploy it in server.

Step 5 :- Now create a new AuthoringTemplate and click on localizations link on top and select your Text Provider and corresponding property.


Step 6 :- Now click ok and then view authoring template in english and spanish




Note :- Please observe the name difference krshna and krishna is changing based on loaded language.

Custom single threaded java server

 package com.diffengine.csv; import java.io.*; import java.net.*; import java.util.Date; public class Server { public static void main(Str...