Bonnes Pratiques Webtop
Cet article donne un ensemble de bonnes pratiques pour les développements réalisés sous Webtop.
Sommaire
Votre avis
Current user rating: 11/100 (1 votes)
|
|
Organisation des extensions
Un composant Webtop est défini par plusieurs fichiers:
- Un fichier XML pour le décrire.
- Une ou plusieurs pages JSP.
- Un fichier dictionnaire contenant les messages.
- Une classe d'instance.
Le composant de d'affichage d'une recherche, sur une installation 5.3, est pris pour exemple pour illustrer la mise en place de l'extension. Ce composant est intéressant, car la définition faite au niveau Webtop est déjà une extension de la définition dans la couche Webcomponent.
Définition standard
Pour cette version, le fichier XML se trouve à l'emplacment webtop/config/searchex_component.xml
avec le contenu suivant:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Confidential Property of Documentum, Inc. -->
<!-- (c) Copyright Documentum, Inc. 2001. -->
<!-- All Rights reserved. -->
<!-- May not be used without prior written agreement -->
<!-- signed by a Documentum corporate officer. -->
<!-- -->
<!-- Component: search -->
<!-- Scope: None -->
<!-- Revision $revision$ -->
<!-- Modified on $date$ -->
<config version='1.0'>
<!-- this component doesn't handle display of search results of a dm_query object -->
<scope>
<!-- the simple search component definition -->
<component id="search" extends="search:webcomponent/config/library/search/searchex/search_component.xml">
<!-- Component Behavior -->
<class>com.documentum.webtop.webcomponent.search.SearchEx</class>
</component>
</scope>
</config>
Cette définition est donc une extension du composant défini à l'emplacement webcomponent/config/library/search/searchex/search_component.xml
dont le contenu est:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Confidential Property of Documentum, Inc. -->
<!-- (c) Copyright Documentum, Inc. 2001. -->
<!-- All Rights reserved. -->
<!-- May not be used without prior written agreement -->
<!-- signed by a Documentum corporate officer. -->
<!-- -->
<!-- Revision $revision$ -->
<!-- Modified on $date$ -->
<config version='1.0'>
<!-- this component doesn't handle display of search results of a dm_query object -->
<scope>
<!-- the simple search component definition -->
<component id="search">
<!-- Description (not NLS'd) -->
<desc>
You can use the search component to do the following:
1. Perform search queries.
2. Display the search results.
</desc>
<params>
<!-- the query string. Its content type is specified queryType -->
<param name="query" required="true"></param>
<!-- a value "objectId": specify the object id of the smartlist -->
<!-- a value "querydef": specify the XML content of a smartlist -->
<!-- a value "queryId": (internal)specify the an active query for editing -->
<!-- a value "string" or null: specify the keywords -->
<param name="queryType" required="false"></param>
<!-- for non-dql query: specify whether to use streamline view; defaults to true -->
<param name="drilldown" required="false"></param>
<!-- for non-dql query: specify whether to show wait page; defaults to true -->
<param name="showwait" required="false"></param>
</params>
<!-- Component Layout -->
<pages>
<filter clientenv='not appintg'>
<start>/webcomponent/library/searchresultslist/searchex/wait.jsp</start>
</filter>
<filter clientenv='appintg'>
<start>/webcomponent/library/searchresultslist/searchex/appintgwait.jsp</start>
</filter>
<filter clientenv='not appintg'>
<classic>/webcomponent/library/searchresultslist/searchex/searchresults_list.jsp</classic>
</filter>
<filter clientenv='appintg'>
<classic>/webcomponent/library/searchresultslist/searchex/appintg_searchresults_list.jsp</classic>
</filter>
<streamline>/webcomponent/library/searchresultslist/searchex/searchresults_drilldown.jsp</streamline>
</pages>
<!-- Component Behaior -->
<class>com.documentum.webcomponent.library.search.SearchEx</class>
<nlsbundle>com.documentum.webcomponent.library.search.SearchExNlsProp</nlsbundle>
<!-- If this component supports failover/replication, the failoverenabled needs to be set to true-->
<failoverenabled>true</failoverenabled>
<!-- Component specific Configuration -->
<!-- default search docbases and sources -->
<!-- a value of "current_docbase": search the current docbase -->
<!-- a value of "visible_docbases": search all the visible docbase -->
<!-- a value of "preferred_sources": search the preferred sources -->
<!-- a value of "all_sources": all the visible docbases and external sources -->
<defaultsources>preferred_sources</defaultsources>
<!-- Indicate if the path information should be displayed for results coming from a docbase.-->
<!-- Fetching folder information may be an expensive operation -->
<displayresultspath>true</displayresultspath>
<!-- default object type for the search -->
<type>dm_sysobject</type>
<!-- 'true' active or 'false' de-active term-hit highlighting -->
<highlight_matching_terms>true</highlight_matching_terms>
<!-- visibility and order of attribute columns -->
<!-- attribute names starting with uppercase are pseudo -->
<columns_drilldown>
<loadinvisibleattribute>true</loadinvisibleattribute>
<column>
<attribute>object_name</attribute>
<label><nlsid>MSG_NAME</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>Location</attribute>
<label><nlsid>MSG_ATTR_LOCATION</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>title</attribute>
<label><nlsid>MSG_ATTR_TITLE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>authors</attribute>
<label><nlsid>MSG_AUTHORS</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>a_content_type</attribute>
<label><nlsid>MSG_FORMAT</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>r_content_size</attribute>
<label><nlsid>MSG_SIZE</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>owner_name</attribute>
<label><nlsid>MSG_OWNER_NAME</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>group_name</attribute>
<label><nlsid>MSG_GROUP_NAME</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_creator_name</attribute>
<label><nlsid>MSG_CREATOR_NAME</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_object_type</attribute>
<label><nlsid>MSG_OBJECT_TYPE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_version_label</attribute>
<label><nlsid>MSG_VERSION_LABEL</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_creation_date</attribute>
<label><nlsid>MSG_CREATION_DATE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_modify_date</attribute>
<label><nlsid>MSG_MODIFIED_DATE</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>r_modifier</attribute>
<label><nlsid>MSG_MODIFIER</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_access_date</attribute>
<label><nlsid>MSG_ACCESS_DATE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_lock_owner</attribute>
<label><nlsid>MSG_LOCK_OWNER</nlsid></label>
<visible>true</visible>
</column>
<!-- this is a pseudo attributes refering to the folder path or external source URL -->
<column>
<attribute>Source</attribute>
<label><nlsid>MSG_ATTR_SOURCE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>summary</attribute>
<label><nlsid>MSG_ATTR_SUMMARY</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>topic_status</attribute>
<label><nlsid>MSG_DISCUSSION</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>room_status</attribute>
<label><nlsid>MSG_ROOM_ICON</nlsid></label>
<visible>true</visible>
</column>
</columns_drilldown>
<!-- visibility and order of attribute columns -->
<!-- attribute names starting with uppercase are pseudo -->
<columns_list>
<loadinvisibleattribute>true</loadinvisibleattribute>
<column>
<attribute>object_name</attribute>
<label><nlsid>MSG_NAME</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>score</attribute>
<label><nlsid>MSG_ATTR_SCORE</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>summary</attribute>
<label><nlsid>MSG_ATTR_SUMMARY</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>title</attribute>
<label><nlsid>MSG_ATTR_TITLE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>authors</attribute>
<label><nlsid>MSG_AUTHORS</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>a_content_type</attribute>
<label><nlsid>MSG_FORMAT</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_content_size</attribute>
<label><nlsid>MSG_SIZE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>owner_name</attribute>
<label><nlsid>MSG_OWNER_NAME</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>group_name</attribute>
<label><nlsid>MSG_GROUP_NAME</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_creator_name</attribute>
<label><nlsid>MSG_CREATOR_NAME</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_object_type</attribute>
<label><nlsid>MSG_OBJECT_TYPE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_version_label</attribute>
<label><nlsid>MSG_VERSION_LABEL</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_creation_date</attribute>
<label><nlsid>MSG_CREATION_DATE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_modify_date</attribute>
<label><nlsid>MSG_MODIFIED_DATE</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>r_modifier</attribute>
<label><nlsid>MSG_MODIFIER</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_access_date</attribute>
<label><nlsid>MSG_ACCESS_DATE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_lock_owner</attribute>
<label><nlsid>MSG_LOCK_OWNER</nlsid></label>
<visible>false</visible>
</column>
<!-- this is a pseudo attributes refering to the folder path or external source URL -->
<column>
<attribute>Location</attribute>
<label><nlsid>MSG_ATTR_LOCATION</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>Source</attribute>
<label><nlsid>MSG_ATTR_SOURCE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>topic_status</attribute>
<label><nlsid>MSG_DISCUSSION</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>room_status</attribute>
<label><nlsid>MSG_ROOM_ICON</nlsid></label>
<visible>true</visible>
</column>
</columns_list>
<!-- visibility and order of attribute columns -->
<!-- attribute names starting with uppercase are pseudo -->
<columns_saved_search>
<loadinvisibleattribute>true</loadinvisibleattribute>
<column>
<attribute>object_name</attribute>
<label><nlsid>MSG_NAME</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>Location</attribute>
<label><nlsid>MSG_ATTR_LOCATION</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>title</attribute>
<label><nlsid>MSG_ATTR_TITLE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>authors</attribute>
<label><nlsid>MSG_AUTHORS</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>a_content_type</attribute>
<label><nlsid>MSG_FORMAT</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>r_content_size</attribute>
<label><nlsid>MSG_SIZE</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>owner_name</attribute>
<label><nlsid>MSG_OWNER_NAME</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>group_name</attribute>
<label><nlsid>MSG_GROUP_NAME</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_creator_name</attribute>
<label><nlsid>MSG_CREATOR_NAME</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_object_type</attribute>
<label><nlsid>MSG_OBJECT_TYPE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_version_label</attribute>
<label><nlsid>MSG_VERSION_LABEL</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_creation_date</attribute>
<label><nlsid>MSG_CREATION_DATE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_modify_date</attribute>
<label><nlsid>MSG_MODIFIED_DATE</nlsid></label>
<visible>true</visible>
</column>
<column>
<attribute>r_modifier</attribute>
<label><nlsid>MSG_MODIFIER</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_access_date</attribute>
<label><nlsid>MSG_ACCESS_DATE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>r_lock_owner</attribute>
<label><nlsid>MSG_LOCK_OWNER</nlsid></label>
<visible>true</visible>
</column>
<!-- this is a pseudo attributes refering to the folder path or external source URL -->
<column>
<attribute>Source</attribute>
<label><nlsid>MSG_ATTR_SOURCE</nlsid></label>
<visible>false</visible>
</column>
<column>
<attribute>summary</attribute>
<label><nlsid>MSG_ATTR_SUMMARY</nlsid></label>
<visible>true</visible>
</column>
</columns_saved_search>
<dragdrop>
<sourceactions>
</sourceactions>
<targetactions>
<targetaction>com.documentum.web.formext.control.dragdrop.CopyToFolderTargetAction</targetaction>
<targetaction>com.documentum.web.formext.control.dragdrop.LinkToFolderTargetAction</targetaction>
<targetaction>com.documentum.web.formext.control.dragdrop.ImportTargetAction</targetaction>
</targetactions>
<dataproviders>
<dataprovider>
<format>com.documentum.web.formext.control.dragdrop.ObjectIdData</format>
<provider>com.documentum.web.formext.control.dragdrop.ObjectIdDataProvider</provider>
</dataprovider>
<dataprovider>
<format>com.documentum.web.formext.control.dragdrop.FileDescriptorData</format>
<provider>com.documentum.web.formext.control.dragdrop.FileDescriptorDataProvider</provider>
</dataprovider>
<dataprovider>
<format>com.documentum.web.formext.control.dragdrop.FileContentsData</format>
<provider>com.documentum.web.formext.control.dragdrop.FileContentsDataProvider</provider>
</dataprovider>
</dataproviders>
</dragdrop>
</component>
</scope>
</config>
Extension
Extension XML
Afin d'identifier précisément les fichiers étendus, il est recommander de créer dans le répertoire custom/config trois sous répertoires:
- wdk: Pour les définitions des composant étendant les définitions de la couche wdk.
- webcomponent: Pour les définitions des composant étendant les définitions de la couche webcomponent.
- webtop: Pour les définitions des composant étendant les définitions de la couche webtop.
Puis dans chacun des ces sous répertoire, il faut recréer l'arborescence de l'emplacement du composant étendu. Ainsi lors de la lecture des personnalisations, il est aisé de retrouver l'emplacement de la définition étendue.
Dans le cadre de cet exemple, seul le sous répertoire webtop est créé. Le fichier pour l'extension se trouve à l'emplacement custom/config/webtop/searchex_component.xml
:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<config version='1.0'>
<scope>
<component id="search" extends="search:webtop/config/searchex_component.xml">
<pages>
<filter clientenv='not appintg'>
<start>/webcomponent/library/searchresultslist/searchex/wait.jsp</start>
</filter>
<filter clientenv='appintg'>
<start>/webcomponent/library/searchresultslist/searchex/appintgwait.jsp</start>
</filter>
<filter clientenv='not appintg'>
<classic>/custom/webcomponent/library/searchresultslist/searchex/searchresults_list.jsp</classic>
</filter>
<filter clientenv='appintg'>
<classic>/webcomponent/library/searchresultslist/searchex/appintg_searchresults_list.jsp</classic>
</filter>
<streamline>/webcomponent/library/searchresultslist/searchex/searchresults_drilldown.jsp</streamline>
</pages>
<class>fr.amexio.webtop.webcomponent.search.SearchEx</class>
<nlsbundle>fr.amexio.webcomponent.library.search.SearchExNlsProp</nlsbundle>
</component>
</scope>
</config>
Dans cette définition les extensions concernent:
- La page pour le mode classic, et hors intégration dans une application, originalement définie dans la couche webcomponent.
- La classe d'instance originalement définie dans la couche webtop.
- Le dictionnaire de message défini dans la couche webcomponent.
Extension des jsp
Afin d'identifier rapidement rapidement la page jsp étendue, seul les deux premiers niveau du répertoire est remplacé par l'identifiant de l'application. Dans le cadre de cet exemple, l'application est identifiée par fr.amexio, en remplacement de com.documentum. La page jsp étendue se trouve à l'emplacement webcomponent/library/searchresultslist/searchex/searchresults_list.jsp
, l'extension est stockée à l'emplacement custom/webcomponent/library/searchresultslist/searchex/searchresults_list.jsp
.
Il est également très important de conserver le formatage du fichier original, même si celui ci ne présente aucune indentation. Ainsi, il sera aisé de réaliser des comparaisons sur les pages originales et les extensions.
Extension dictionnaire
Afin d'identifier rapidement rapidement le dictionnaire étendu, seul les deux premiers niveau du répertoire est remplacé par l'identifiant de l'application. Dans le cadre de cet exemple, l'application est identifiée par fr.amexio, en remplacement de com.documentum. Le dictionnaire étendue étant com.documentum.webcomponent.library.search.SearchExNlsProp, l'extension est stockée à l'emplacement custom/strings/fr/amexio/webcomponent/library/search/SearchExNlsProp
.
Dans le cadre de cette extension, seul le titre est modifié. Tous les autres messages sont conservés à l'identique grâce à l'instruction NLS_INCLUDE
référençant le fichier original.
NLS_INCLUDES=com.documentum.webcomponent.library.search.SearchExNlsProp
MSG_TITLE=My Advanced Search
Dans le cadre des dictionnaires, le fichier étendu est donc identifiable par l'emplacement et son contenu.
Extension classe d'instance
Afin d'identifier rapidement rapidement la classe étendue, seul les deux premiers niveau du package est remplacé par l'identifiant de l'application. Dans le cadre de cet exemple, l'application est identifiée par fr.amexio
, en remplacement de com.documentum
. La classe étendue étant com.documentum.webtop.webcomponent.search.SearchEx
, l'extension est créé sous la classe fr.amexio.webtop.webcomponent.search.SearchEx
.
A noter que cela ne respecte pas les bonnes pratique JAVA qui indique qu'il ne faut pas donner le même nom de classe pour l'extension que celle étendue. Mais dans le cadre de Webtop, cela est particulièrement pratique.
Dans le code présenté ci dessous, seule la méthode buildQueryFromKeywords(String keywords)
est étendue:
package fr.amexio.webtop.webcomponent.search;
import com.documentum.fc.client.search.IDfExpressionSet;
import com.documentum.fc.client.search.IDfQueryBuilder;
import com.documentum.fc.client.search.IDfQueryDefinition;
import com.documentum.fc.client.search.IDfSearchOperation;
import com.documentum.fc.client.search.IDfSmartListDefinition;
import com.documentum.fc.common.DfAttr;
import com.documentum.fc.common.DfDocbaseConstants;
import com.documentum.webcomponent.library.search.SearchInfo;
/**
* @author Etienne Jouvin
*
*/
public class SearchEx extends com.documentum.webtop.webcomponent.search.SearchEx {
private static final String DESC_RECOVER = "Recover";
/**
* Serial version UID
*/
private static final long serialVersionUID = 8483322094034597915L;
/** {@inheritDoc} */
// @Override
protected void buildQueryFromKeywords(String keywords) {
super.buildQueryFromKeywords(keywords);
/* Get the SearchInfo instance where the query definition is stored. */
SearchInfo searchInfo = getSearchInfo();
/* Get the smart list definition. */
IDfSmartListDefinition idfSmartListDefinition = searchInfo.getSmartListDefinition();
IDfQueryDefinition idfQueryDefinition = idfSmartListDefinition.getQueryDefinition();
if (idfQueryDefinition instanceof IDfQueryBuilder) {
/*
* The query definition must be a IDfQueryBuilder, because built like this is in parent method. Do the check in case of...
*/
IDfQueryBuilder idfQueryBuilder = (IDfQueryBuilder) idfQueryDefinition;
/* Get the root expression, where filter can be added. */
IDfExpressionSet rootExpressionSet = idfQueryBuilder.getRootExpressionSet();
rootExpressionSet.addSimpleAttrExpression(DfDocbaseConstants.DESCRIPTION, DfAttr.DM_STRING, IDfSearchOperation.SEARCH_OP_EQUAL, true, false, DESC_RECOVER);
}
}
}
Ici, nous n'expliquerons pas l'utilité de l'extension.