Translate

Showing posts with label FatWire. Show all posts
Showing posts with label FatWire. Show all posts

Sunday, September 6, 2015

Using Groovy elements in WCS

One of the new features which were introduced with Oracle WebCenter Sites version 11.1.1.8.0 was use of Groovy within WCS. You can now write code in Groovy elements to perform business logic separately and hence, with proper plan and design, one can develop a site with MVC pattern.

Although there is not much documentation or explanation on how to use it. There are few interesting articles by Oracle expert team which should be helpful:

1. Why to use groovy with WCS?
This article explains not only how WCS product uses groovy element but possible use of it to design MVC pattern within WCS sites.

2. Wrapper-CSElement example using Groovy
Although it's not a simple example as one would like but you get the point once you go through it.

3. Using RUNTAG api
This is far most best example explaining use of groovy to render sites tags. Best part of using groovy is that it can invoke both JSP and XML tags.

4. An useful use case
Setting http-status codes, content-type at runtime and redirect implementation; which may be desirable for many clients.

5. Get Translated asset
Describes the method to get a translation of an asset using Groovy.

6. Groovy CSELement Dispatcher
A good example on how to leverage groovy to generate output in different formats by setting content-type at runtime. This use case is very simple yet very useful and powerful considering that if your clients wants to have WCS site based content output in different formats for e.g. generating different web feed formats (like atom or rss), json object to be consumed by other sites or internally, XML/HTML output of certain webpage, etc.

All of the above examples mentioned are really good in terms of providing knowledge and implementation of groovy element.

Groovy was already used before it was officially being introduced to Sites with GSF framework. Currently, WCS product itself doesn't use many groovy elements but a few. It seems after the introduction of groovy, in future, more of development should occur within product (or sample sites) which shall make full use of groovy language to develop a site or product itself. Henceforth, it is better for any Sites developer to learn groovy and be prepared to use it.

----------------------------------------------------
SUGGESTIONS/COMMENTS ARE INVITED
----------------------------------------------------



Friday, April 3, 2015

Example 14: Searching Assets using Lucene Search API

Hello, this blog corresponds to the chapter - Public Site Search from Oracle WebCenter Sites developer's guide but also applies to FatWire 7.x version too.

Before jumping into example, one should know the architecture behind lucene search used in Sites/FatWire:

There are 2 types of indexes: Global and AssetType. Default attributes present in
1. Global indexes is defaultSearchField which contains all the following: asset type, asset subtype, name, description, status, createdby, updatedby, updateddate, startdate, enddate, fw_uid, id, fw_tags, all asset's flex attributes. Other attributes are also stored as stated in guide. All the indexes are stored under <WCS_Installed_Folder>/shared/lucene/Global
2. AssetType indexes - All the metadata in defaultSearchField and rest attributes in seperate columns as stated in guide. All the indexes are stored under <WCS_Installed_Folder>/shared/lucene/<AssetType>

This indexes can be checked via one tool - LUKE

You should check out this chapter in Admin Guide for configuring lucene indexes and once you know how to configure, you can proceed with coding to search assets via lucene search API.

When to use what?

Global indexes are used for searching against any asset types, hence, then name Global index and Public Site Search. You can search against multiple asset types given that there is a common attribute like name, description, createdby, etc. or even if you have created your flex family in such a way that all the asset types fall under one Attribute type and there is one common attribute among all the definition, that attribute can used for Global/Public site search.
AssetType indexes as you can guess is limited to only one Asset Type search.

Common methods and their description are provided in Guide here. You can also browse through javadoc to see various methods.

Example: The following example can be used to search against AVIArticle for AviSports site which comes along with JSK 11g. Enable AVIArticle lucene index and enable GLOBAL indexes for AVIArticle too. Add the attributes like headline, abstract, postDate, etc. for indexing. Once done, proceed with creation of one template - SearchLayout (type: Page and usage: can be used as Layout and add 2 params in cache-criteria - keyword and form-to-render) and just save. Create one Page asset with nothing in it, just a name should suffice, and assign this template SearchLayout. (You can also place this page under AviSports home page so that it will be visible in top navig)

Copy and paste code form Page/ArticleLayout.jsp to this template - SearchLayout. Delete the main container code from the template which would look like this:
This snippet was taken from HomeLayout template present in 11.1.1.6.0 JSK

Thus, now all the code will be under between container id.

First, just a simple form tag with one input field like text with name="keyword" (keyword search will be performed against headline or abstract field for AVIArticle asset). Replace the <form> tag into <satellite:form> tag (don't forget to include satellite tag lib at the top of your template).

Use the tag: <render:gettemplateurlparameters> to generate URL for this page itself (Same page will be called after the form is submitted) and render all the args name and value inside <satellite:form> as hidden params. Check the tag here.  (don't forget to include string tag lib at the top of your template). It should end up like this:

Once search form is completed, proceed with search lucene search logic as shown.


and then, just load the query and show the results as required:

































You can download the source code from here.

Update: In latest 11g version, you have the ability to configure vanity URLs per asset. So if you have vanity URL enabled, then the above search may not work. There are 2 or more possible solutions, I am listing 3 of them:
1. Apply Patch 2 or greater and replace <satellite:form> with <form> tag. Pass action url in form and remove passing of hidden params via <render:geturltemplateparameters> tag.
2. Another way is to delete vanity URL entry for the page asset. Go to your page asset, search for the URL tab, copy the URL and go to Admin UI -> System tools -> double click URL -> Select "URL" as search criteria, paste the URL which you copied and then search. Select the entry and click delete, this will remove vanity URL for the page asset. Check your search page asset, there should be no vanity URL in URL tab. Above code will work with this configuration.
3.  Don't pass action url, this way you get form but again no vanity url.

Notes:

1. If you want to build global site search, then following changes should be done. Note: There should be at least one common attribute to search against.

IndexSourceMetadata metadata = con.getConfiguration( "Global" );
QueryExpression typeQ = new QueryExpressionImpl(SearchIndexFields.Global.ASSET_TYPE, Operation.EQUALS, "AVIArticle");
typeQ = typeQ.or(SearchIndexFields.Global.ASSET_TYPE, Operation.EQUALS, "AVIImage");

2. If you want to search against Parent assets. For e.g. finding AVIArticles with parent "Skiiing", use filter: FieldCopier to copy parent id in one attribute and enable this attribute for indexing and update your query to search against that indexed attribute name.

3. Similar above steps can be done to search against associated content.


----------------------------------------------------
SUGGESTIONS/COMMENTS ARE INVITED
----------------------------------------------------



Saturday, March 7, 2015

Example 13: Create, update and delete Asset (Asset API Write)

This section of blog lists how to create, update and delete assets (flex, basic and flex parents only) using Asset API. Most of examples are present in Developer's guide which can be accessed here -> http://docs.oracle.com/cd/E29542_01/doc.1111/e29634/asset_api_tutorial.htm#WBCSD2403

All examples for creating, updating and deleting assets are already present.
Although methods are defined in developer's guide, but some are missing, so I have listed those:
1. Updating an asset's attribute of type-asset

a.getAttributeData("<Attribute Name>").setDataAsList(Arrays.<AssetId>asList( new AssetIdImpl( "<ASSET TYPE>", <ASSET ID in LONG>)));

2. Get an asset's locale

data.getAttributeData("Dimension").getData());

3. Avoid getting parent's attribute value if child has no attribute value by setting immediateOnly

query.getProperties().setIsImmediateOnly(true);

4. While querying asset, you can set Site condition as shown:

query.getProperties().setSite(<SITE ID in Long>);

5. While querying asset, you can set locale condition only if you have copied its name to some other custom attribute via flex filter

6. Get parents or immediate parents

java.util.List<AssetId> parents = data.getImmediateParents();
java.util.List<AssetId> parents = data.getParents();

NOTE: Before using those methods mentioned in guide, please note that:
  1. Flex family or Basic asset family should already be created i.e. framework must be ready
  2. For flex -> attributes, flex parent definition, flex content definition and flex filters must be present too.
  3. Considering that you have FSIISite in your installation, examples provided in guide are valid
General steps to follow:
    1. Get a session
    2. Get a handle to AssetDataManager
    3. Use appropriate method to
      • CREATE - AssetDataManager.insert( List<AssetData> data )
      • UPDATE - AssetDataManager.update( List<AssetData> data )
      • DELETE - AssetDataManager.delete( List<AssetData> data )
    4. Use the above API with care and always handle all exceptions with logging

----------------------------------------------------
SUGGESTIONS/COMMENTS ARE INVITED
----------------------------------------------------





Example 12: Rendering Basic and Flex Asset (Asset API Read)

Asset API are nothing but FatWire / Oracle WebCenter Sites JAVA API which provides classes to perform CRUD operation on assets. This were created in order to use them in non-servlet context, such as standalone java programs. Thus, this API can be used regardless of servlet framework as stated in guide.

Following code snippet is taken from guide and I have updated it little bit for blog purpose only.

You can go through full Asset API chapter here -> http://docs.oracle.com/cd/E29542_01/doc.1111/e29634/asset_api_tutorial.htm#WBCSD2387

Reading Data provided Asset Type and Asset Id

// Following 2 lines are always required if you want to use Asset API
// Don't forget to include correct java classes
Session ses = SessionFactory.getSession();
AssetDataManager mgr =(AssetDataManager) ses.getManager( AssetDataManager.class.getName() );

// After getting the AssetDataManager object, we use it to read the asset data by using method - readAttributes(<AssetType:AssetId>,<List of attributes>)

// First set the id in AssetId object as shown
AssetId id = new AssetIdImpl( <AssetType as String>, <AssetId in Long> );

// Create list of attributes; even for single attribute have to generate list only
List attrNames = new ArrayList();
attrNames.add( "name" );
attrNames.add( "description" );

//Now read attributes using mgr.readAttributes method and print output
AssetData data = mgr.readAttributes( id, attrNames );
AttributeData attrDataName = data.getAttributeData( "name" );
AttributeData attrDataDescr = data.getAttributeData( "description" );
//Output
out.println( "name:" + attrDataName.getData() );
out.println( "<br/>" );
out.println( "description:" + attrDataDescr.getData() );
out.println( "<br/>" );

//Above example was for the case of loading a single asset id (<assettype>:<assetid in Long>) to readAttributes method
//Multiple AssetIds can be processed via the AssetManager.read(List<AssetId> ids) method as shown below (For single AssetId object, we have to pass it as list only) and get all attributes:
Iterable<AssetData> dataItr = mgr.read( Collections.singletonList( id ) );

for( AssetData data : dataItr )
{
  for(AttributeData atrData : data.getAttributeData() )
  {
    out.println( "<br/>" );
    out.println( "attribute name:" + atrData.getAttributeName() );
    out.println( "data: " + atrData.getData() );
  }
}

Reading data on basis of some Criteria - Using Query

//For example: If you want to search against particular attribute
//Note: This example is totally copied from the developer guide
//We use Condition class to create the criteria for search
//Query class to process this criteria and generate query
//Read the Query using AssetManager.read(Query query) method as shown
<%@ page import="com.fatwire.system.*"%>
<%@ page import="com.fatwire.assetapi.data.*"%>
<%@ page import="com.fatwire.assetapi.query.*"%>
<%@ page import="java.util.*"%>
<cs:ftcs>
<%
Session ses = SessionFactory.getSession();
AssetDataManager mgr = (AssetDataManager) ses.getManager( AssetDataManager.class.getName() );
Condition c = ConditionFactory.createCondition( "FSIISKU", OpTypeEnum.EQUALS, "iAC-008" );
Query query = new SimpleQuery( "Product_C", "FSII Product", c, Collections.singletonList( "name" ) );

for( AssetData data : mgr.read( query ) )
{
AttributeData attrData = data.getAttributeData( "name" );
out.println( "name:" + attrData.getData() );
out.println( "<br/>" );
out.println( "id:" + data.getAssetId() );
}
%>
</cs:ftcs>
// Read other topics from the guide:

Saturday, March 8, 2014

Example 6: Creating URLs for Hyperlinks


Creating URLs for hyperlinks:
Following instructions are for generating URLs for any asset type within FatWire/Oracle WebCenter Sites 11g.

GENERAL STEPS TO FOLLOW:
  • Add render taglib to your JSP.
  • Generally, you need to know few parameters like asset type(c), asset id(cid), parent id(p), packedargs(packedargs), arguments to pass (render:argument)
  • Use render:getpageurl, render:getbloburl, render:gettemplateurl and render:gettemplateurlparameters according to your requirement and generate the output variable.
  • Use string:stream to render the output variable wherever required. (Don't forget to add String taglib to your JSP)
CASE 1: render:getpageurl : This tag creates URLs for assets that are not blobs. NOTE: if you are creating links to assets that are being rendered through templates, you should use the render:gettemplateurl tag instead. This tag creates a URL for an asset, processing the arguments passed to it from the calling element into a URL-encoded string and returning it in a variable.

<render:getpageurl pagename="SiteCatalogPageEntry"
       cid='<%=ics.GetVar("cid")%>'
       c="AssetType"
       wrapperpage="WrapperPage"
       outstr="theURL"/>

CASE 2: render:bloburl : Creates a BlobServer URL without embedding it in an HTML tag and thus, provides an output variable which can be used inside img tag or other.

<render:getbloburl
       blobtable="ImageFile"
       blobcol="urlpicture"
       blobheader='<%=ics.GetVar("asset:mimetype")%>'
       blobkey="id"
       blobwhere='<%=ics.GetVar("asset:id")%>'
       outstr="theURL"/>
<img src='<%=ics.GetVar("theURL")'/>

CASE 3: render:gettemplateurl : Generates a valid URL to an asset, rendered through a template, with optional wrapper page support. User-defined arguments will be packed if wrapperpage is specified. This tag is the preferred method for generating a URL to an asset (provided that the asset is being rendered through a Template, which is the recommendation). It effectively replaces render:getpageurl in most (but certainly not all) cases. Instances of this tag must contain information about who the caller is in order to operate correctly. The caller must be either another Template or a CSElement. This tag will not operate correctly without valid information about the caller i.e. need to provide tid and ttype parameters.

<render:gettemplateurl
       outstr="aUrl"
       c='AssetType'
       cid='AssetId'
       tname='TemplateName (mostly it is layout)'
       wrapperpage='Wrapper' >
</render:gettemplateurl>

CASE 4: render:gettemplateurlparameters : This tag does not create any url but looks up all of the URL parameters that would have been set into a URL and returns them in the form of a List so that can be passed as used as required. Basically used in Satellite:form as below.

<%-- Look up the parameters --%>
<render:gettemplateurlparameters
       outlist="args"
       args="c,cid"
       tname='<%=ics.GetVar("LayoutVar")%>'
       wrapperpage='<%=ics.GetVar("WrapperVar")%>'>
   <render:argument name="p" value='<%=ics.GetVar("p")%>'/>
</render:gettemplateurlparameters>
<satellite:form method="post" id="AddToCartForm">
   <%-- Loop through all of the url parameters and set them
        into the form as hidden fields so the data is sent
        back to Sites as needed.  These variables will include
        pagename, wrapperpage, c, cid, p, possibly rendermode
        and possibly others. --%>
   <ics:listloop listname="args">
       <input type="hidden"
              name="<string:stream list="args" column="name"/>"
              value="<string:stream list="args" column="value"/>" />
   </ics:listloop>
</satellite:form>

CASE 4: satellite:link : This tag generates URL to a page (pagename in SiteCatalog entry) which is present in the OracleWCS/FatWire.

<satellite:link pagename="PAGENAME" outstr="theURL">
 <satellite:parameter name="param_name" value="param_value"/>
</satellite:link>

INFO:
  • Most of time, render:gettemplateurl is used to generate urls for assets
  • While creating URLs in Template or CSElement, developer should keep in mind to include all the parameters by passing them via arguments (render:arguments) so that no errors are found from assembler when it tries to create vanity urls.
----------------------------------------------------
SUGGESTIONS/COMMENTS ARE INVITED
----------------------------------------------------


Sunday, December 8, 2013

Example 5: Searching Assets

Searching assets is very basic functionality required in various online sites whether be a content search, tagged-content search or even media asset search. Content (Assets) can be any assets like product assets, article assets, etc.

Following instructions are for searching FLEX assets using searchstate tags.

GENERAL STEPS TO FOLLOW:
  1. For using searchstate tag, add the searchstate taglib at starting of your JSP/XML. 
  2. Create an empty searchstate object (using searchstate:create tag), which can contain 2 operations: "and" & "or".
  3. Add constraint to the searchstate i.e. adding a condition for restricting search based on single attribute or another searchstate (also called as nested constraint). For adding constraint, use anyone of the following tag as required: searchstate:addlikeconstraint, searchstate:addnestedconstraint, searchstate:addrangeconstraint, searchstate:addsimpleconstraint, searchstate:addsimplestandardconstraint, searchstate:addstandardconstraint, etc. according to you requirement. 
  4. Set the searchstate (Using assetset:setsearchedassets tag)
  5. Get the required attribute values (Using assetset:getmultiplevalues or assetset:getattributevalues)
  6. Then list through the result (Using ics:listloop and ics:listget tag)
CASE 1: A simple case: Finding attributes of a flex asset to search against value of one attribute

<searchstate:create name="ss" />
<searchstate:addsimplelikeconstraint name="ss" attribute="cat2" value="Watt%"/>
<assetset:setsearchedassets name="as" constraint="ss" assettypes="Products"/>
<assetset:getattributevalues name="as" attribute="productdesc" listvarname="resultlist"/>
<ics:listloop listname="resultlist">
<ics:listget listname="resultlist" fieldname="value"/><br/>
</ics:listloop>


Apart from using searchstate tags, there are other tags which can be used for searching assets (flex or basic or table data) which are described briefly below:
  1. ics:sql - It executes inline SQL statement. You can write a SQL query and search against tablename which should be registered SYTEMINFO table.
  2. ics:callsql - It retrieves and executes a SQL query stored in the SYSTEMSQL table
  3. ics:sqlexp - This tag is used only to build where clause based on given set of parameters. It does not execute any statement. It passes a column name and an expression that contains the column name to be used as the left side in the where clause.
  4. ics:selectto - It executes a simple query from a table, which is equivalent to run a simple SQL query like select * from tablename
  5. asset:search - It locates a list of asset primary table rows based on the asset type and a set of search criteria. Criteria can be defined which can narrow your search. Not recommended for searching FLEX assets.
  6. asset:list - This tag queries the database and retrieve a list of assets that meets the specified criteria. It creates a list of assets of one type. Specific criteria could be against field/value of certain tablename, passing argument in field name/value pairs, etc. to restrict the list.
Detailed explanation is provided in Tag Reference/Developer guide.

INFO:
  • The above case is very simple case provided by tag reference itself.
  • Check the examples and details of every searchstate tag in TagReference and Developer Guide
  • Following is the list which shows which searchstate tags to use for what case:
    • searchstate:addsimplestandardconstraint - Adds an attribute name/single value constraint to an existing searchstate object.
    • searchstate:addlikeconstraint - Adds a list of attribute like name/value constraints into a new or existing searchstate object.
    • searchstate:addnestedconstraint - Nests a searchstate as a constraint within another searchstate.
    • searchstate:addrangeconstraint - Adds a range constraint to a searchstate on a specific attribute.
    • searchstate:addsimplelikeconstraint - Adds an attribute like name/value constraint into a new or existing searchstate object.
    • searchstate:addstandardconstraint - Adds a list of attribute name/value constraints into a new or existing searchstate object.

----------------------------------------------------
SUGGESTIONS/COMMENTS ARE INVITED
----------------------------------------------------


Monday, November 25, 2013

Example 7: Site Plan

This example illustrates how to render SITE PLAN in different cases.

CASE 1: If you know Page name or asset id.

GENERAL STEPS TO FOLLOW:
  1. Load the page asset (using asset:load tag) 
  2. Get the site node from SitePlanTree table (using asset:sitenode tag) 
  3. Load the node (using siteplan:load tag)
  4. Get ChildList from loaded node (using siteplan:children tag or using siteplan:listpages tag)
  5. Loop through childlist to get Page name/id (using ics:listloop tag) 
a) Using siteplan:children tag

<asset:load name="target" type='Page' field="name" value="Home" site="<%=ics.GetVar("site")%>"/>
<!--  Get site node -->
<asset:getsitenode name="target" output="PageNodeId"/>
<!-- Load Home page as a siteplan node object -->
<siteplan:load name="ParentNode" nodeid='<%=ics.GetVar("PageNodeId") %>'/>
<!-- Obtain Home page's child node, save in list and order them by their rank -->
<siteplan:children name="ParentNode" list="ChildPages" order="nrank" code="Placed" objecttype="Page"/>
<!-- Loop through list to get page names's under Home page node -->
<ics:if condition='<%=ics.GetList("ChildPages") !=null %>'>
<ics:listloop listname="ChildPages">
<ics:listget listname="ChildPages" fieldname="id" output="aid"/>
<asset:load name="ThePage" type="Page" objectid='<%=ics.GetVar("aid") %>' />
<p><asset:get field="name"/></p>
</ics:listloop>
</ics:if>

b) Using siteplan:listpages tag (continue after loading the parent node (using siteplan:load) as shown above)

<!-- Query the SitePlanTree table and then creates a list of pages, starting with the page node that you specify. -->

<siteplan:listpages name="ParentNode" placedlist="placedPages" level="1" />
<!-- Loop through list to get page names under specified page node -->
<ics:if condition='<%=ics.GetList("placedPages") != null %>'>
<ics:listloop listname="placedPages">
<p><ics:listget listname="placedPages" fieldname="PageName"/></p>
</ics:listloop>

</ics:if>



CASE 2: Querying from root node i.e. Publication Node of the site. This is required when you want to extract and display information about the site structure from the top down. You can even list the pages which are placed or unplaced.

GENERAL STEPS TO FOLLOW:
  1. Load the publication (using publication:load tag) 
  2. Get the publication id (using publication:get tag)
  3. Query the SitePlanTree table for a root node of the site plan (using siteplan:root tag)
  4. Loop through list to get publication nid (using ics:listloop tag) 
  5. Load the node (using siteplan:load tag)
  6. Get ChildList from loaded node (using siteplan:children tag)
  7. Again loop through childlist if there child pages are required as shown in CASE 1
<publication:load name="thisPub" field="name" value='<%=ics.GetVar("site") %>'/>
<publication:get name="thisPub" field="id" output="thePubID"/>
<siteplan:root list="PubRoot" objectid='<%=ics.GetVar("thePubID") %>'/>
<ics:if condition='<%=ics.GetList("PubRoot") != null %>'>
<ics:listloop listname="PubRoot">
<ics:listget listname="PubRoot" fieldname="nid" output="rootNodeid"/>
<siteplan:load name="RootNode" nodeid='<%=ics.GetVar("rootNodeid") %>'/>
<siteplan:children name="RootNode" list="RootChildPages" order="nrank" code="Placed" objecttype="Page"/>
<ics:if condition='<%=ics.GetList("RootChildPages") !=null %>'>
<ics:listloop listname="RootChildPages">
<p><ics:listget listname="RootChildPages" fieldname="name"/></p>
</ics:listloop>
</ics:if>
</ics:listloop>
</ics:if>

INFO:
  • Using siteplan tags can be trickier when you want specific information, so please read about them before you use them.
  • While coding for siteplan, always keep in mind what table column we are getting after the query. Read the tags properly, its written there.
  • Keep CS Explorer (FatWire)\ Sites Explorer (Oracle WCS) handy to see which field's/column's value you are retrieving.
----------------------------------------------------
SUGGESTIONS/COMMENTS ARE INVITED
----------------------------------------------------

Saturday, November 16, 2013

Example 11: Basic Guidelines for using TAGS


Hi All, I would be adding here tips & tricks for using tags which are used in FatWire/Oracle WebCenter Sites. This post would be always be alive and I would be adding new findings as I learn more.
  1. Never hardcore assettypes and specifically, assetids in tags i.e. don't write them as they are present in FatWire. This is very important because after publishing your site from environment to other, assetids changes and hence, hardcording is never an option. Use tags to retrieve assetids. (Faced one such issues while working with 11g) For eg: If you want assetid of  a Page Asset, just load the Page asset using <asset:load> by providing name/value pair and retrieve assetid or use Template/CSElement mapping (render:lookup tag). This helps when 2 assets have same name but you have mapped the correct required one in the MAP.
  2. Read what tag does before you use them. This is really important as I have seen people in past using tags without reading them and suffering from long hours of resolving many issues. For eg: Retrieving a flex asset using asset:load is NOT recommended. Site would work with no issues even if you use asset:load to retrieve flex assets, but later on when you site grows, you will face many performance issues. Hence, use correct tags to retrieve assets.
  3. Check the attributes which are included while using tags. For eg: use of 'scoped' attribute while calling CSElement via render:callelement tag. Please read documentation before using any tags to leverage their full use. Another thing which I noticed in performance was using some tags attributes properly. For e.g. Using <ics:listloop> tag; suppose you want only 2 results, use maxrows argument so that loop does not iterate over full list, its just like adding break in for loop.
  4. This may be new to many. XML tags and JSP tags can perform different in functionality. You may get some attributes/tags which are available in XML but not in JSPs and vice versa.
  5. Use tags which sets compositional dependencies for cache management automatically. FatWire is all about Caching and Designing. If your design (creation of minimal flex family and basic family, less number of templates, proper use of subtype dispatching, etc. ) is proper and Caching strategies are well prepared, your site would be very fast and fluid. Some tags are unaware of what type of assets they are going to be deal with and hence, those tags generates undeterminable dependencies , which may again lead to performance issues. Eg: use <render:unknowndeps> when you querying for large number of assets. Please read about dependencies from documentation, it is very necessary to know about them.
  6. Retrieving One attribute vs Multiple attributes: This may seems like very easy but again when your site grows large, you may face performance issues. For eg: Consider asset:load tag to retrieve basic asset. After using this tag, if you code to get every attribute of its asset using asset:get tag, it tries to fetch info every-time from db which is very performance costly, so use asset:scatter which will retrieve the required attributes in one go. Similarly is the case with flex assets. Check out assetset:getattributevalues and assetset:getmultiplevalues in tag reference.
  7. Search tags: Searching assets via asset:search or asset:list is very costly than using searchstate tags for large amount of data. Check the use of searchstate tags explained in one of my blogs.
  8. Always perform NULL checks and make use of  ics:geterrno to check if your tags threw any error. For eg: After retrieving attributes of flex assets in list, we should always check if the list is empty or not.
  9. Flush the variables which are not required using ics:removevar or ics:removessvar. This may seem like waste of line of code but let me give you one example of its use. Suppose, you are looping through list of assets and retrieving their attributes and setting in HashMap, we can make use of one variable to assign that value and remove its variable after putting in Map for the next data to be set. Eg: If we have list of username set in Map with no values and you want their ages to be set in values, so rather than calling a particular template repeatedly, its better to use loop. For eg:                                                                                                    <%for(Entry<String,String> entry: userMap.entrySet())                                                                                        { %> <render:callelement elementname='GetAge' scoped="global" >                                               <render:argument name="name" value='<%= entry.getKey() %>'/></render:callelement>                             <%  if(Utilities.goodString(ics.GetVar("age"))){userMap.put(entry.getKey(),ics.GetVar("age"));} ics.RemoveVar("age");}%>
  10. Use CatalogManager tags wisely, they have ability to delete/edit database tables.
  11. Passing arguments: Developers often tend to forget to include the arguments in cache criteria, when we pass any argument to call other template from current template. 
  12. Passing multiple values: Pass as comma separated values as one string while passing through arguments in tags. Less arguments - less dependencies. Avoid large number of arguments as possible.
  13. Use tags for date formatting, decimals, currency and string provided by Fatwire rather than using Java classes.
  14. You might use same variable in one template, either remove that variable after its use or use the variable as - Variables.assettype:fieldname
  15. Use ics.RegisterList("IList Name",null) to de-register the list which would avoid any clashing between two lists on same page with same name.
  16. Sometimes, we require asset name, page name or their asset ids which are not associated with our assets or page and hence, these can not be generated on template or CSElement dynamically. For eg: Suppose you want to load homepage on your template for generating siteplan, so you end up using asset:load to load the page either with its name or id, which is again hardcoding values. So to avoid that, use "Map" functionality in CSElement or Template where you can provide key-value and bind the page asset with template, ensuring intended asset is called dynamically. Use render:lookup tag for this.
  17. Variables: GLOBAL vs LOCAL - Global variables (including reserved variables) have more precedence than Local variables. For e.g. "site" variable which is present in URL act as Global variable. So suppose you want to pass site names to some particular element to get some value and if you are using variable - "site", you are in trouble because using "site" variable will provide you same value which is present in URL in the calling template.
  18. Try to minimize loading of assets. For e.g. Rather than using asset:load tag and then using asset:children tag to get association, don't use asset:load. You can directly load association by providing asset id and asset type info to <asset:children> tag (Check how in tag reference)
  19. If you want to know metadata attributes of flex or basic asset, use <asset:load> and <asset:scatter> tag. <asset:scatter> tag has ability to scatter all the metadata attributes of the loaded asset using asset:load tag.

----------------------------------------------------
SUGGESTIONS/COMMENTS ARE INVITED
----------------------------------------------------

Example 8: Satellite forms

Satellite Forms: Can be used via tag - satellite:form, which emits an HTML <form> tag suitable for using in a Satellite Server, Sites, or mixed Sites-Satellite Server environment. It eliminates the need to have to specify the action parameter, and by doing so, gives control over the action URL to the Satellite Server tags. Forms generated using satellite:form tag can be used to replace all input forms.

GENERAL STEPS TO FOLLOW:
  1. Replace <form> tag with <satellite:form> tag 
  2. Import the satellite and string tld
  3. Use <render:gettemplateurlparameters> to generate the URL where you want to submit the form
  4. Loop through outlist generated by above tag inside form as hidden parameter
  5. Also include one hidden parameter for eg: ftp (form-to-process) which would be passed along with other hidden parameters in packedargs variable.
  6. Process/Pass the arguments starting from Wrapper -> Layout -> (Subtype Dispatching) Specific form processing Template or CSElement to required output template. Use render:unpackarg tag to retrieve variables from packedargs strings
  7. Don't forget to add the parameters in cache criteria of corresponding Template/SiteEntry.
CASE 1: A very simple login form

</render:gettemplateurlparameters outlist="args" 
tid='<%=ics.GetVar("eid")%>' slotname="loginForm"
site='<%=ics.GetVar("site")%>'
c='<%=ics.GetVar("c")%>'
cid='<%=ics.GetVar("cid")%>'
wrapperpage="<Wrapper_Name>"  
tname="/<Layout_Name>" >
</render:gettemplateurlparameters>

<satellite:form  method="GET" >
     <label>Enter Username and Password</label>
     <input type="text" name="username" value=""/>
     <input type="password" name="password" value=""/>
     <input type="hidden" name="ftp" value="loginForm"/>
     <input type="submit" name="login" value="login" class="submit"/>
     <ics:listloop listname="args">
          <input type="hidden" name='<string:stream list="args" column="name"/>'                                              value='<string:stream list="args" column="value"/>' />
     </ics:listloop>
</satellite:form>

INFO:
  • In render:gettemplateurlparameters tag, we need to specify which page we want to submit the request. Hence, the value should be c='Page' and cid='<AssetId of the page>'. Please note don't hardcore assetid, use <asset:load> tag to load page asset and get the assetid.
  • Method can be GET/POST. URL assemblers are only invoked on GET requests. They are not invoked on POST requests. For example, when accessing a page with a GET request, the URL assembler is invoked to disassemble the URL. It then provides the appropriate parameters that Content Server requires to open that page (such as c, cid, and pagename) by adding them to the definition (if they do not already exist in the definition). However, when a request is POSTed, such as a form with method=post, the URL assembler is not invoked to disassemble the URL. Example for a proper POST form given in CASE 2.
  • JavaScript validations which applies to HTML <form> are also applicable for <satellite:form> tag.
  • In above example, WebCenter Sites shows the username and password in the URL after submitting the form which is very threat to user sensitive information, so the parameters Content Server requires to open the page must be part of the post request itself and hence, we need to pass them as show below.

CASE 2: A complex POST form which works with assembler. POST request require both, action in form and rendering of hidden parameters to work with URL assembler.

<asset:load name="PageName" type="Page" field="name" value="ProcessLogin" site='<%=ics.GetVar("site") %>'/>
<asset:get name="PageName" field="id" output="pageId"/>



<render:gettemplateurl
outstr="outLink"
site='<%=ics.GetVar("site") %>'
wrapperpage="<Wrapper_Name>"
tname='ProcessLogin'
tid='<%=ics.GetVar("tid") %>'
ttype='CSElement'
c='Page'
cid='<%=ics.GetVar("pageId")%>'
slotname="processlogin"
assembler='<assemblerShortName>' >
</render:gettemplateurl>

<render:gettemplateurlparameters 
outlist="args" 
tid='<%=ics.GetVar("tid")%>'
slotname="loginform"
site='<%=ics.GetVar("site")%>'
c="Page"
cid='<%= ics.GetVar("pageId") %>' 
tname="<Layout>"
wrapperpage="<Wrapper_Name>">
</render:gettemplateurlparameters>



<satellite:form  method="POST" action='<%=ics.GetVar("outlink")%>'>
     <label>Enter Username and Password</label>
     <input type="text" name="username" value=""/>
     <input type="password" name="password" value=""/>
     <input type="hidden" name="ftp" value="loginForm"/>
     <input type="submit" name="login" value="login" class="submit"/>
     <ics:listloop listname="args">
          <input type="hidden" name='<string:stream list="args" column="name"/>'                                              value='<string:stream list="args" column="value"/>' />
     </ics:listloop>
</satellite:form>

After submit, page should go through ProcessLogin template.
ProcessLogin Template may contain code like (After skipping the obvious importing tld codes):


<%     if((ics.GetVar("ftp")!=null && ics.GetVar("ftp").equals("loginForm"))    
{          //Get username, password and check if credentials are valid and redirect to correct page     
} else {          
// Redirect to login page with showing some error if login info was wrong or ftp variable did not exist in variable pool    

%>


INFO:
  • For form to work with POST request we require both action and hidden url parameters to be passed to work with Assembler (UPDATE: If you are using vanity URLs, then you don't need to pass hidden params generated via <render:gettemplateurlparameters> and have to pass action url in satellite:form tag which will be generated via <render:gettemplateurl> tag. Also include your assembler short name while generating action url, if no assembler, then pass assembler="query")
  • You may/may not require to pass argument while generating url parameters depending upon how your assembler is coded
  • action in form is generated via <render:gettemplateurl> and hidden parameters are passed using <render:gettemplateurlparameters>. Please read about this tags before using them.
  • In Case 2 example, we are submitting the form to other template (ProcessLogin) which processes the login request. For processing, we have passed one hidden parameter (ftp - form-to-process), so that we can check its value in ProcessLogin template and decide on what to do and respond accordingly.
  • Many other points are to be taken care while creating forms, as form processing may undergo JavaScript validation, ajax call for verification of login info (in our case) with 3rd party APIs, processing of some hidden variables passed in Wrapper, keeping the user in session after successful login or showing error if failed, creating/handling cookies, visitor tracking via Engange module (Personalization), etc. All this could vary from site to site and obviously depends on customer requirements.
  • There is introduction of vanity URLs in new WCS 11g (11.1.1.8.0 onwards) where in every asset can have vanity URLs if configured (Its done for avisports in JSK). If you have configured vanity url for a page asset and if you are searching by passing page asset id and template to generate action url, above search may not work. Hence, to resolve this you can do one of the following: EITHER delete the vanity url for this page asset (by doing so, there is no conflict of urls but you will not get vanity url on search which is not desirable) OR use <form> tag rather than using <satellite:form> & pass action url, don't pass hidden params which are generated via <render:gettemplateurlparamaters> tag (by doing so, you are just forward request to a particular page and if there are any params, then those will also be passed along with it) 
  • It seems you cannot pass query params (more than 1) if you are using vanity urls and hence, you will have to apply PATCH 2 or higher so that you can pass query param strings like param1=val1&param2=val2
----------------------------------------------------
SUGGESTIONS/COMMENTS ARE INVITED
----------------------------------------------------