Translate

Showing posts with label forms. Show all posts
Showing posts with label forms. Show all posts

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, November 16, 2013

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
----------------------------------------------------