What is Hybris Release Patch Structure

Eray Araz
5 min readMar 7, 2023

--

Using this structure from the Hybris standard, you can automatically import impex during the update. For this reason, it is used in very large projects to ensure that the impexes that need to be import are regular and to prevent problems that may occur at deploy nights. Also, this structure is both safer because your QA engineer friends do not import impex, and it can prevent problems on days when you forget to give impex to your friend :)

How it will be implemented

First we will create a new extension

  • Run ant extgen within the platform
  • Press enter to select empty template
  • Name the extension and a new extension will be created

Let’s add the extension path to the localextension file

  • Add the 2 extensions in the image to your file. Arazpatches is my extension I just named. You give your own extension name
  • You should see your own extension as below.

Edit the extension setup file as follows.

package com.arazpatches.setup;

import com.arazpatches.constants.ArazpatchesConstants;
import de.hybris.platform.core.initialization.SystemSetup;
import de.hybris.platform.core.initialization.SystemSetup.Type;
import de.hybris.platform.core.initialization.SystemSetupContext;
import de.hybris.platform.core.initialization.SystemSetupParameter;
import de.hybris.platform.core.initialization.SystemSetupParameterMethod;
import de.hybris.platform.patches.AbstractPatchesSystemSetup;
import de.hybris.platform.patches.Patch;
import de.hybris.platform.util.SystemSetupUtils;

import java.util.List;

@SystemSetup(extension = ArazpatchesConstants.EXTENSIONNAME)
public class ArazpatchesSystemSetup extends AbstractPatchesSystemSetup {

@Override
@SystemSetup(type = Type.ESSENTIAL, process = SystemSetup.Process.INIT)
public void createEssentialData(final SystemSetupContext setupContext)
{
super.createEssentialData(setupContext);
}
@Override
@SystemSetup(type = Type.PROJECT, process = SystemSetup.Process.ALL)
public void createProjectData(final SystemSetupContext setupContext)
{
super.createProjectData(setupContext);
}
@Override
@SystemSetupParameterMethod
public List<SystemSetupParameter> getInitializationOptions()
{
boolean isInit = SystemSetupUtils.isInit((SystemSetupContext)null);
if(!isInit) {
return super.getInitializationOptions();
}
return null;
}
@Override
protected SystemSetupParameter createSystemSetupParameterBasedOnNotSelectedProperty(final Patch patch)
{
return super.createSystemSetupParameterBasedOnNotSelectedProperty(patch);
}
}
   <bean id="arazpatchesSystemSetup" class="com.arazpatches.setup.ArazpatchesSystemSetup" parent="patchesSystemSetup">
<!-- constructor arg injection example -->
</bean>

Create a structure file and create the 2 classes I added below


package com.arazpatches.structure;


public enum Release implements de.hybris.platform.patches.Release
{

R1("01"), R2("02"), R3("03");

private String releaseId;

Release(final String releaseId)
{
this.releaseId = releaseId;
}

@Override
public String getReleaseId()
{
return this.releaseId;
}

}

package com.arazpatches.structure;


public enum StructureState implements de.hybris.platform.patches.organisation.StructureState
{
V1, V2, V3, LAST;

@Override
public boolean isAfter(final de.hybris.platform.patches.organisation.StructureState structureState)
{
if (this == structureState)
{
return false;
}
for (final de.hybris.platform.patches.organisation.StructureState iterateValue : values())
{
if (structureState.equals(iterateValue))
{
return true;
}
if (this.equals(iterateValue))
{
return false;
}
}
return false;
}
}

We will create the abstract patch file. You can give any name you want.

package com.arazpatches.release;

import de.hybris.platform.patches.Patch;
import de.hybris.platform.patches.organisation.ImportLanguage;

import java.util.Set;

public interface ArazPatch extends Patch {

void createGlobalData(final Set<ImportLanguage> languages, boolean updateLanguagesOnly);

}
package com.arazpatches.release;


import com.arazpatches.constants.ArazpatchesConstants;
import de.hybris.platform.core.initialization.SystemSetup;
import de.hybris.platform.patches.AbstractPatch;
import de.hybris.platform.patches.Release;
import de.hybris.platform.patches.internal.logger.PatchLogger;
import de.hybris.platform.patches.internal.logger.PatchLoggerFactory;
import de.hybris.platform.patches.organisation.ImportLanguage;
import de.hybris.platform.patches.organisation.StructureState;

import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

import static de.hybris.platform.patches.internal.logger.PatchLogger.LoggingMode.HAC_CONSOLE;


@SystemSetup(extension = ArazpatchesConstants.EXTENSIONNAME)
public abstract class AbstractArazPatch extends AbstractPatch implements ArazPatch {
private static final PatchLogger LOG = PatchLoggerFactory.getLogger(AbstractArazPatch.class);

public AbstractArazPatch(String patchId, String patchName, Release release, StructureState structureState) {
super(patchId, patchName, release, structureState);
}

@Override
public void createProjectData(final StructureState structureState) {
final boolean update = structureState != this.structureState;
createGlobalData(structureState, update);
}

protected void createGlobalData(final StructureState structureState, final boolean update) {
//The language structure can be configured in this method.
Set<ImportLanguage> importLanguages = new HashSet<>();
String message = "Creating global data for Eray Araz Patch";
final String languages = importLanguages.stream().map(ImportLanguage::getCode).collect(Collectors.joining(","));
LOG.info(HAC_CONSOLE, message, languages);
createGlobalData(importLanguages, update);
}


}
    <bean id="abstractArazPatch" class="com.arazpatches.release.AbstractArazPatch" abstract="true"
parent="abstractPatch"/>

Now we generate our patch classes

package com.arazpatches.release;

import com.arazpatches.structure.Release;
import com.arazpatches.structure.StructureState;
import de.hybris.platform.patches.organisation.ImportLanguage;

import java.util.Set;

public class Patch1x0x00 extends AbstractArazPatch {

public Patch1x0x00() {
super("1.0.00", "01_00_00", Release.R1, StructureState.V1);
}

@Override
public void createGlobalData(final Set<ImportLanguage> languages, final boolean updateLanguagesOnly) {

importGlobalData("r01_00_00_user-groups.impex", languages, updateLanguagesOnly);
}
}

    <bean id="patch1x0x00" class="com.arazpatches.release.Patch1x0x00" parent="abstractArazPatch"/>
package com.arazpatches.release;

import com.arazpatches.structure.Release;
import com.arazpatches.structure.StructureState;
import de.hybris.platform.patches.organisation.ImportLanguage;

import java.util.Set;

public class Patch1x0x01 extends AbstractArazPatch {

public Patch1x0x01() {
super("1.0.01", "01_00_01", Release.R1, StructureState.V1);
}

@Override
public void createGlobalData(final Set<ImportLanguage> languages, final boolean updateLanguagesOnly) {

importGlobalData("r01_00_01_user-groups.impex", languages, updateLanguagesOnly);
}

}
    <bean id="patch1x0x01" class="com.arazpatches.release.Patch1x0x01" parent="abstractArazPatch"/>
    <bean id="arazpatchesSystemSetup" class="com.arazpatches.setup.ArazpatchesSystemSetup" parent="patchesSystemSetup">
<property name="patches">
<list>
<ref bean="patch1x0x00"/>
<ref bean="patch1x0x01"/>
</list>
</property>
</bean>

Now let’s create our impex file structure

  • Your file structure should be as follows. Otherwise impex cannot find your files. This is because you give patch Id and pathNames this way. If you change these, the file structure also changes.
  • There must be one global Header mandatory. Don’t forget this.

GlobalHeader.impex

$contentCatalog=bookstoreContentCatalog
$languages=en,tr,de,fr,nl,es,it
$lang=en

$contentCatalog=bookstoreContentCatalog
$contentCV=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$contentCatalog]),CatalogVersion.version[default=Staged])[default=$contentCatalog:Staged]
$wideContent=CMSImageComponent,BannerComponent

$jarResourceCmsSms=jar:com.bookstore.patches.setup.ArazpatchesSystemSetup&/bookstorepatches/import/sms
$jarResourceCms=jar:com.bookstore.patches.setup.ArazpatchesSystemSetup&/bookstorepatches/import/emails
$jarEmailResource=jar:com.bookstore.patches.setup.ArazpatchesSystemSetup&/arazpatches/import/emails

$emailPackageName=com.bookstore.email.context
$siteLogo=SimpleBannerComponent

$productCatalog = bookstoreProductCatalog
$catalogVersion = catalogversion(catalog(id[default = $productCatalog]), version[default = 'Staged'])[unique = true, default = $productCatalog:Staged]

userGroup.impex

INSERT_UPDATE UserGroup; uid[unique = true]; locname[lang = en]; backOfficeLoginDisabled[default = false]
; arazAdmin ; Yetkili Kullanıcı ;
  • Finally, you need to add the following features to your local extension file.
  • patches.1_0.not Selected=true -> This means that these impexes will not be imported during the update. I chose this way because I can change it through HAC. I’ll show you how I do it below. I don’t want this to be out of my control.

update.executeProjectData.extensionName.list=arazpatches
patches.1_0.notSelected=true
patches.1_1.notSelected=true
patches.allow.rerun.patches=true

Now let’s get the server up and start an update on hac and test it.

You can check the impex status here. If there is an error, there are also error logs.

I’m adding a link below for other articles I’ve written. You can check it out if you want to read.

--

--

Eray Araz

Java Software Developer. I work with companies to development new projects. I write blog about interesting problems I encounter.