meta data for this page
  •  

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
sap_hybris_commerce:sap_hybris_persistence_mechanism [2019/08/26 16:15] – created Antonio Robirosasap_hybris_commerce:sap_hybris_persistence_mechanism [2022/11/25 08:06] (current) – [One to many relations] Antonio Robirosa
Line 77: Line 77:
  
   * **Database Tables:** Use the deployment tag to specify the table where the instances of this type or relation are going to be stored. A recommended practice is to do this with every type which is a direct subclass of Item or GenericItem and every relation. See [[https://wiki.hybris.com/display/release4/Specifying+a+Deployment+for+hybris+Platform+Types|https://wiki.hybris.com/display/release4/Specifying+a+Deployment+for+hybris+Platform+Types]]   * **Database Tables:** Use the deployment tag to specify the table where the instances of this type or relation are going to be stored. A recommended practice is to do this with every type which is a direct subclass of Item or GenericItem and every relation. See [[https://wiki.hybris.com/display/release4/Specifying+a+Deployment+for+hybris+Platform+Types|https://wiki.hybris.com/display/release4/Specifying+a+Deployment+for+hybris+Platform+Types]]
- +  * If you specify a table for a Hybris Type which already has one, like Product, you will see duplicate row in HMC when ordering by the product attribute (Version 6.1). The sql create by the flexible search query service will join the tables incorrectly.
-If you specify a table for a Hybris Type which already has one, like Product, you will see duplicate row in HMC when ordering by the product attribute (Version 6.1). The sql create by the flexible search query service will join the tables incorrectly. +
   * **Serializable:** Declare a //serialVersionUID%// field if the item could be used in a Collection. Hybris stores Collection in a blog field in the database after serializing the object. You may have [[http://www.javapractices.com/topic/TopicAction.do?Id=45|incompatibilities with future changes if you don't set your own serialVersionUID]]. See:   * **Serializable:** Declare a //serialVersionUID%// field if the item could be used in a Collection. Hybris stores Collection in a blog field in the database after serializing the object. You may have [[http://www.javapractices.com/topic/TopicAction.do?Id=45|incompatibilities with future changes if you don't set your own serialVersionUID]]. See:
   * Don't change the package of an Hybris type or prepare yourself for unexpected errors during the update running system with the actual instances of the type.   * Don't change the package of an Hybris type or prepare yourself for unexpected errors during the update running system with the actual instances of the type.
Line 93: Line 91:
     * The field can only be written once (initial=true)     * The field can only be written once (initial=true)
     * The field must be removed when the parent Item is removed (partof=true)     * The field must be removed when the parent Item is removed (partof=true)
 +
 +<WRAP center round important 100%>
 +Hybris don't trigger the remove interceptors when updating a partof relations. If a base product is updated with a **subset** of the variants which are on the database, **the missing variants will be removed** and you can't use a remove interceptor to prevent the deletion. This happens on SAP commerce 1905. \\
 +To really prevent the removal of products from the database you need a database trigger like the following one for Microsoft SQL Server:
 +<code>
 +return jaloSqlScriptService.runDeleteOrUpdateStatement("CREATE OR ALTER TRIGGER PRODUCTS_DEL ON products INSTEAD OF DELETE AS THROW 51000, 'Products must not be deleted', 1")
 +
 +</code>
 +This code create database trigger preventing any removal of products. It depends on [[https://github.com/arobirosa/areco-deployment-script-manager/wiki|Areco Deployment Script Manager]]
 +
 +</WRAP>
 +
     * The field is part of the secondary key and must be **unique** inside the cluster of servers (unique=true). A group of attributes could be unique. The validation is done by Hybris using Java code. As two threads may store two items with the same unique values on the database, you have to use database transactions to be sure that the fields are unique across the cluster of servers     * The field is part of the secondary key and must be **unique** inside the cluster of servers (unique=true). A group of attributes could be unique. The validation is done by Hybris using Java code. As two threads may store two items with the same unique values on the database, you have to use database transactions to be sure that the fields are unique across the cluster of servers
     * [[https://help.hybris.com/6.5.0/hcd/8bff7a568669101488a5e40cb7bbd0b9.html#itemsxmlelementreference-type_modifierstype|Other modifiers]]     * [[https://help.hybris.com/6.5.0/hcd/8bff7a568669101488a5e40cb7bbd0b9.html#itemsxmlelementreference-type_modifierstype|Other modifiers]]
Line 139: Line 149:
   * Attributes can be **localized** and there would be one value for each locale. Internally Hybris uses a map<Locale, AttributeType>:   * Attributes can be **localized** and there would be one value for each locale. Internally Hybris uses a map<Locale, AttributeType>:
  
-<code> +<code xml
-<attribute qualifier="description" type="localized:java.lang.String">    <description>Description of the state.</description>    <persistence type="property"/></attribute>+<attribute qualifier="description" type="localized:java.lang.String"> 
 +    <description>Description of the state.</description> 
 +    <persistence type="property"/> 
 +</attribute>
 </code> </code>
  
Line 149: Line 162:
   * Hybris doesn't remove old attributes when you remove them from the files *-items.xml. If you remove a mandatory attribute, you must set it as optional, remove the setters and getters:   * Hybris doesn't remove old attributes when you remove them from the files *-items.xml. If you remove a mandatory attribute, you must set it as optional, remove the setters and getters:
  
-<code>+<code xml>
 <attribute qualifier="id" type="java.lang.String"> <attribute qualifier="id" type="java.lang.String">
   <description>DEPRECATED: hybris doesn't remove old mandatory attributes, so we keep it.</description>   <description>DEPRECATED: hybris doesn't remove old mandatory attributes, so we keep it.</description>
Line 159: Line 172:
 After an update running system in production, you could remove it. This means that it takes two releases to remove it.\\ The best alternative is to use the [[http://sourceforge.net/projects/arecodeploymentscriptsmanager/|Areco Deployment Script Manager]] and remove the old attribute using a deployment script. After an update running system in production, you could remove it. This means that it takes two releases to remove it.\\ The best alternative is to use the [[http://sourceforge.net/projects/arecodeploymentscriptsmanager/|Areco Deployment Script Manager]] and remove the old attribute using a deployment script.
  
-  * Hybris can't guarantee the uniqueness of a group of attributes which have the modifier **unique**. As the uniqueness is check on the Java code side, [[https://wiki.hybris.com/x/kaCPBg|you could end with duplicate rows in the database coming from different threads on one server or from different servers in a cluster]]. A good practice is to declare a unique index for the Hybris type. This will create an index on the database. [[https://wiki.hybris.com/x/Ypf4DQ|The uniqueness in Hybris depends on the mechanism you are using.]] +  * Hybris can't guarantee the uniqueness of a group of attributes which have the modifier **unique**. As the uniqueness is check on the Java code side, you could end with duplicate rows in the database coming from different threads on one server or from different servers in a cluster. A good practice is to declare a unique index for the Hybris type or [[https://help.sap.com/viewer/d0224eca81e249cb821f2cdf45a82ace/1905/en-US/8c7387f186691014922080f2e053216a.html|use transactions]] for objects which must be consistent like stock. 
 ====== Relations between Hybris Types ====== ====== Relations between Hybris Types ======
  
 ===== One to many relations ===== ===== One to many relations =====
  
-<code> +<code xml
-<relation code="Customer2EmailAddress" generate="true" localized="false" autocreate="true">    <sourceElement qualifier="customer" type="Customer" cardinality="one"/>    <targetElement qualifier="emails" type="EmailAddress" cardinality="many" collectiontype="list" ordered="true"/></relation>+<relation code="Customer2EmailAddress" generate="true" localized="false" autocreate="true"> 
 +    <sourceElement qualifier="customer" type="Customer" cardinality="one"/> 
 +    <targetElement qualifier="emails" type="EmailAddress" cardinality="many" collectiontype="list" ordered="true"/> 
 +</relation>
 </code> </code>
  
 This example creates the column **customer** in the table where the items EmailAddress are stored and getters and setters on the customers to set and get the list of emails. The sourceElement and targetElement may have modifiers like the attributes. You have to read the source and target elements XML tags crossed to understand where the setters and getters are generated. This example creates the column **customer** in the table where the items EmailAddress are stored and getters and setters on the customers to set and get the list of emails. The sourceElement and targetElement may have modifiers like the attributes. You have to read the source and target elements XML tags crossed to understand where the setters and getters are generated.
  
 +One to many relations cannot be localized. You have to use a many to many relationship and manage the removal of associations.
 ===== Many to many relations ===== ===== Many to many relations =====
  
-<code> +<code xml
-<relation code="InterestGroupVoucherRestrictionToInterestGroupRelation" localized="false" generate="true" autocreate="true">    <deployment table="voucherToInterestGroup" typecode="15189"/>    <sourceElement qualifier="voucherRestrictions" type="InterestGroupRestriction" cardinality="many" />    <targetElement qualifier="interestGroups" type="InterestGroup" cardinality="many" /></relation>+<relation code="InterestGroupVoucherRestrictionToInterestGroupRelation" localized="false" generate="true" autocreate="true"> 
 +    <deployment table="voucherToInterestGroup" typecode="15189"/> 
 +    <sourceElement qualifier="voucherRestrictions" type="InterestGroupRestriction" cardinality="many" /> 
 +    <targetElement qualifier="interestGroups" type="InterestGroup" cardinality="many" /> 
 +</relation>
 </code> </code>
  
Line 181: Line 201:
 ====== Hybris Enumerations ====== ====== Hybris Enumerations ======
  
-<code> +<code xml
-<enumtypes>    <enumtype code="SystemPhase" dynamic="false" >        <value code="INITIALIZATION" />        <value code="UPDATE" />    </enumtype></enumtypes>+<enumtypes> 
 +    <enumtype code="SystemPhase" dynamic="false" > 
 +        <value code="INITIALIZATION" /> 
 +        <value code="UPDATE" /> 
 +    </enumtype> 
 +</enumtypes>
 </code> </code>
  
-This static enumeration is generated as the Java enum org.areco.ecommerce.deploymentscripts.**enums**.SystemPhase and can be referenced in any attribute of Hybris types. **The list of values can only changed during compilation time by changing the items.xml file.**\\ If you want to change the values of an enumeration during **runtime**, creating values with hmc or importing them with Impex you have to declare an enumeration as dynamic:+This static enumeration is generated as the Java enum org.areco.ecommerce.deploymentscripts.**enums**.SystemPhase and can be referenced in any attribute of Hybris types. **The list of values can only changed during compilation time by changing the items.xml file.**\\ 
 +If you want to change the values of an enumeration during **runtime**, creating values with hmc or importing them with Impex you have to declare an enumeration as dynamic:
  
-<code> +<code xml
-<enumtype code="StockLevelStatus" generate="true" autocreate="true" dynamic="true">    <description>Flag for real stock level status</description>    <value code="inStock" />    <value code="outOfStock" /></enumtype>+<enumtype code="StockLevelStatus" generate="true" autocreate="true" dynamic="true"> 
 +    <description>Flag for real stock level status</description> 
 +    <value code="inStock" /> 
 +    <value code="outOfStock" /> 
 +</enumtype>
 </code> </code>
  
Line 202: Line 232:
       * When your field contains a collection of String or Enumeration values.       * When your field contains a collection of String or Enumeration values.
       * When your field is dynamic because you aren't persisting the collection in the database.       * When your field is dynamic because you aren't persisting the collection in the database.
-  * **Getter of a Collection**: %%'''%%The returned Collection should not be modified%%'''%% because the changes are going to be lost or you are going to get an Exception (See [[https://wiki.hybris.com/display/release4/Models#Models-Collections|https://wiki.hybris.com/display/release4/Models#Models-Collections]] and [[https://wiki.hybris.com/display/forum/Adding+new+item+to+collection|https://wiki.hybris.com/display/forum/Adding+new+item+to+collection]]). A new Java collection should be used+  * **Getter of a Collection**: **The returned Collection can'be modified** because you are going to get an Exception[[https://help.sap.com/viewer/d0224eca81e249cb821f2cdf45a82ace/6.5.0.0/en-US/8c146aa686691014bbf6fe76a708ece2.html?q=Models%20collections|A new Java collection should be used]]
   * **Relations with enumerations:** 1-n don't work and m-n can be defined but you may get an error in some machines when running the update running system. A safe approach is to create an item type which relates the enumeration with the other item.   * **Relations with enumerations:** 1-n don't work and m-n can be defined but you may get an error in some machines when running the update running system. A safe approach is to create an item type which relates the enumeration with the other item.
   * **One to Many**: Either endpoint cannot be copied easily because the information of the relation is kept in the instance of each class.   * **One to Many**: Either endpoint cannot be copied easily because the information of the relation is kept in the instance of each class.
   * **Many to Many**: Can be copied and searched. The relations are kept in a separated table, so they can be searched with FlexibleQuery or SQL.   * **Many to Many**: Can be copied and searched. The relations are kept in a separated table, so they can be searched with FlexibleQuery or SQL.
-  * Don't create attributes in relations because they aren't supported by the model layer. If you need a relation with fields, create an association object.+  * Don't create attributes in relations because they aren't supported by the model layer. If you need a relation with fields, create an association object —a new Hybris type—.
  
 ====== How to persist and load items ====== ====== How to persist and load items ======
Line 212: Line 242:
 In every case you must use the **modelService**: In every case you must use the **modelService**:
  
-<code> +<code java
-@Component("deploymentScript2ExecutionConverter")public class DeploymentScript2ExecutionConverter implements Converter<DeploymentScript, ScriptExecutionModel> {  private static final Logger LOG = Logger.getLogger(DeploymentScript2ExecutionConverter.class);  @Autowired  private ModelService modelService;  /*   * (non-Javadoc)      * @see de.hybris.platform.servicelayer.dto.converter.Converter#convert(java.lang.Object)   */  @Override  public ScriptExecutionModel convert(final DeploymentScript source) throws ConversionException {    return this.convert(source, (ScriptExecutionModel) this.modelService.create(ScriptExecutionModel.class)); // Creation of a new item  }  /*   * (non-Javadoc)      * @see de.hybris.platform.servicelayer.dto.converter.Converter#convert(java.lang.Object, java.lang.Object)   */  @Override  public ScriptExecutionModel convert(final DeploymentScript source, final ScriptExecutionModel execution)      throws ConversionException {    ServicesUtil.validateParameterNotNullStandardMessage("source", source);    ServicesUtil.validateParameterNotNullStandardMessage("execution", execution);    if (DeploymentScript2ExecutionConverter.LOG.isDebugEnabled()) {      DeploymentScript2ExecutionConverter.LOG.debug("Creating an script execution model from the deployment script " + source);    }    execution.setExtensionName(source.getExtensionName());                                                         // The model is filled    execution.setScriptName(source.getName());    execution.setResult(null); // The caller must set the result before saving the execution.    execution.setPhase(source.getPhase());    return execution;  }}@Servicepublic class ArecoDeploymentScriptsRunner implements DeploymentScriptRunner {  private static final Logger LOG = Logger.getLogger(ArecoDeploymentScriptsRunner.class);  @Autowired  private ModelService modelService;(...)  private void saveAndLogScriptExecution(final UpdatingSystemExtensionContext context,      final ScriptExecutionModel scriptExecution) {    this.modelService.save(scriptExecution);                                                            // The model is stored into the database    context.logScriptExecutionResult(scriptExecution);  }} +@Component("deploymentScript2ExecutionConverter") 
-</code>+public class DeploymentScript2ExecutionConverter implements Converter<DeploymentScript, ScriptExecutionModel> { 
 +  private static final Logger LOG = Logger.getLogger(DeploymentScript2ExecutionConverter.class);
  
-To **retrieve** the model you may use ModelService#get(de.hybris.platform.core.PK) but you usually use Hybris Query Language **FlexibleSearch** to get items from the database.\\ You can **remove** an item using ModelService#remove(java.lang.Object).\\ You can **update the item with the contents of the database** using ModelService#refresh. If two thread modify simultaneously two instances of the same model containing different values, **the last thread is going to override the changes from the first one**. If you are updating critical models like stock levels you must do it inside a database transaction. Hybris don't have any optimistic locking mechanism like Hibernate ORM.+  @Autowired 
 +  private ModelService modelService;
  
-====== Localization of Hybris types and attributes ======+  /* 
 +   * (non-Javadoc) 
 +   *  
 +   * @see de.hybris.platform.servicelayer.dto.converter.Converter#convert(java.lang.Object) 
 +   */ 
 +  @Override 
 +  public ScriptExecutionModel convert(final DeploymentScript source) throws ConversionException { 
 +    return this.convert(source, (ScriptExecutionModel) this.modelService.create(ScriptExecutionModel.class)); // Creation of a new item 
 +  }
  
-The names and descriptions of the Hybris types, enumerations, relations and attributes can be localized using a property file inside **resources/localization**. For example,+  /* 
 +   (non-Javadoc) 
 +    
 +   @see de.hybris.platform.servicelayer.dto.converter.Converter#convert(java.lang.Objectjava.lang.Object) 
 +   */ 
 +  @Override 
 +  public ScriptExecutionModel convert(final DeploymentScript source, final ScriptExecutionModel execution) 
 +      throws ConversionException { 
 +    ServicesUtil.validateParameterNotNullStandardMessage("source", source); 
 +    ServicesUtil.validateParameterNotNullStandardMessage("execution", execution); 
 +    if (DeploymentScript2ExecutionConverter.LOG.isDebugEnabled()) { 
 +      DeploymentScript2ExecutionConverter.LOG.debug("Creating an script execution model from the deployment script " + source); 
 +    } 
 +    execution.setExtensionName(source.getExtensionName());                                                         // The model is filled 
 +    execution.setScriptName(source.getName()); 
 +    execution.setResult(null); // The caller must set the result before saving the execution. 
 +    execution.setPhase(source.getPhase());
  
-<code> +    return execution; 
-File arecoDeploymentScriptsManager/resources/localization/arecoDeploymentScriptsManager-locales_de.properties(...)type.DeploymentEnvironment.name=Deployment Umgebungentype.DeploymentEnvironment.name.name=Nametype.DeploymentEnvironment.description.name=Beschreibungtype.SystemPhase.name=Phase des Systemstype.SystemPhase.INITIALIZATION.name=Initializationtype.SystemPhase.UPDATE.name=Aktualisierung(...) +  }
-</code>+
  
-This sets the name of a Hybris type, an enumeration and two attributes in German.+}
  
-====== General Recommendations ======+@Service 
 +public class ArecoDeploymentScriptsRunner implements DeploymentScriptRunner {
  
-  * Please read [[https://wiki.hybris.com/display/hybrisALF/Type+System|Hybris' general good practices on defining types.]] Those recommendations aren't on this page+  private static final Logger LOG = Logger.getLogger(ArecoDeploymentScriptsRunner.class);
  
-  * Don't use the menu HMC > System > Types to modify the Hybris types on runtime because you changes will be lost after an update running system+  @Autowired 
 +  private ModelService modelService;
  
-\\ Based on Hybris 6.3+(...)
  
-<!-- +  private void saveAndLogScriptExecution(final UpdatingSystemExtensionContext context, 
-var jcomments=new JComments(64'com_content',%%'/%%component/jcomments%%/'%%); +      final ScriptExecutionModel scriptExecution) { 
-jcomments.setList%%('%%comments-list'); +    this.modelService.save(scriptExecution);                                                            // The model is stored into the database 
-%%//%%-->+    context.logScriptExecutionResult(scriptExecution); 
 +  } 
 +
 +</code>
  
 +To **retrieve** the model you may use ModelService#get(de.hybris.platform.core.PK) but you usually use Hybris Query Language **FlexibleSearch** to get items from the database.\\
 +You can **remove** an item using ModelService#remove(java.lang.Object).\\
 +You can **update the item with the contents of the database** using ModelService#refresh. If two thread modify simultaneously two instances of the same model containing different values, **the last thread is going to override the changes from the first one**. If you are updating critical models like stock levels you must do it inside a database transaction. Hybris don't have any optimistic locking mechanism like Hibernate ORM.
  
-=== Add comment ===+====== Localization of Hybris types and attributes ======
  
- Name (required)+The names and descriptions of the Hybris types, enumerations, relations and attributes can be localized using a property file inside **resources/localization**. For example,
  
- E-mail (required, but will not display)+<code> 
 +File arecoDeploymentScriptsManager/resources/localization/arecoDeploymentScriptsManager-locales_de.properties 
 +(...) 
 +type.DeploymentEnvironment.name=Deployment Umgebungen 
 +type.DeploymentEnvironment.name.name=Name 
 +type.DeploymentEnvironment.description.name=Beschreibung
  
- Website+type.SystemPhase.name=Phase des Systems 
 +type.SystemPhase.INITIALIZATION.name=Initialization 
 +type.SystemPhase.UPDATE.name=Aktualisierung 
 +(...) 
 +</code>
  
-{{:components:com_jcomments:images:smilies::laugh.gif|:D}}{{:components:com_jcomments:images:smilies::lol.gif|:lol:}}{{:components:com_jcomments:images:smilies::smile.gif|:-)}}{{:components:com_jcomments:images:smilies::wink.gif|;-)}}{{:components:com_jcomments:images:smilies::cool.gif|8)}}{{:components:com_jcomments:images:smilies::normal.gif|:-|}}{{:components:com_jcomments:images:smilies::whistling.gif|:-*}}{{:components:com_jcomments:images:smilies::redface.gif|:oops:}}{{:components:com_jcomments:images:smilies::sad.gif|:sad:}}{{:components:com_jcomments:images:smilies::cry.gif|:cry:}}{{:components:com_jcomments:images:smilies::surprised.gif|:o}}{{:components:com_jcomments:images:smilies::confused.gif|:-?}}{{:components:com_jcomments:images:smilies::sick.gif|:-x}}{{:components:com_jcomments:images:smilies::shocked.gif|:eek:}}{{:components:com_jcomments:images:smilies::sleeping.gif|:zzz}}{{:components:com_jcomments:images:smilies::tongue.gif|:P}}{{:components:com_jcomments:images:smilies::rolleyes.gif|:roll:}}{{:components:com_jcomments:images:smilies::unsure.gif|:sigh:}}1000 symbols left +This sets the name of a Hybris type, an enumeration and two attributes in German.
- +
- Notify me of follow-up comments\\ +
  
-[[#|Send]] +====== General Recommendations ====== 
- +  * Please read [[https://www.sap.com/cxworks/article/433893244/Data_Model_Design_with_the_SAP_Commerce_Cloud_Type_System|Hybris' general good practices on defining types.]] Those recommendations aren't on this page 
-[[#|Cancel]] +  * Don't use the menu Backoffice > System > Types to modify the Hybris types on runtime because you changes will be lost after an update running system
- +
-  +
- +
-<!-- +
-function JCommentsInitializeForm() +
-+
-        var jcEditor new JCommentsEditor%%('%%comments-form-comment', true); +
-        jcEditor.initSmiles%%('/%%components/com_jcomments/images/smilies%%/'%%); +
-        jcEditor.addSmile%%('%%:D','laugh.gif'); +
-        jcEditor.addSmile%%('%%:lol:','lol.gif'); +
-        jcEditor.addSmile%%('%%:-)','smile.gif'); +
-        jcEditor.addSmile%%('%%;-)','wink.gif'); +
-        jcEditor.addSmile%%('%%8)','cool.gif'); +
-        jcEditor.addSmile%%('%%:-|','normal.gif'); +
-        jcEditor.addSmile%%('%%:-%%*'%%,'whistling.gif'); +
-        jcEditor.addSmile%%('%%:oops:','redface.gif'); +
-        jcEditor.addSmile%%('%%:sad:','sad.gif'); +
-        jcEditor.addSmile%%('%%:cry:','cry.gif'); +
-        jcEditor.addSmile%%('%%:o','surprised.gif'); +
-        jcEditor.addSmile%%('%%:-?','confused.gif'); +
-        jcEditor.addSmile%%('%%:-x','sick.gif'); +
-        jcEditor.addSmile%%('%%:eek:','shocked.gif'); +
-        jcEditor.addSmile%%('%%:zzz','sleeping.gif'); +
-        jcEditor.addSmile%%('%%:P','tongue.gif'); +
-        jcEditor.addSmile%%('%%:roll:','rolleyes.gif'); +
-        jcEditor.addSmile%%('%%:sigh:','unsure.gif'); +
-        jcEditor.addCounter(1000, %%''%%, ' symbols left', 'counter'); +
-        jcomments.setForm(new JCommentsForm%%('%%comments-form', jcEditor)); +
-+
- +
-if (window.addEventListener) {window.addEventListener%%('%%load',JCommentsInitializeForm,false);+
-else if (document.addEventListener){document.addEventListener%%('%%load',JCommentsInitializeForm,false);+
-else if (window.attachEvent){window.attachEvent%%('%%onload',JCommentsInitializeForm);+
-else {if (typeof window.onload=='function'){var oldload=window.onload;window.onload=function(){oldload();JCommentsInitializeForm();}} else window.onload=JCommentsInitializeForm;}  +
-%%//%%--> +
- +
- +
-[[http://www.joomlatune.com|JComments]]+
  
-  * You are here:   +--Based on Hybris 6.5
-  * [[:|Home]] {{:media:system:images:arrow.png}}  +
-  * Hybris' persistence mechanism+