Documentation Home

2.1 to 3.0 Migration

Broadleaf Commerce version 3.0 represents a huge step forward in our technology and approach. As such, various changes are required to existing version 2.1 installations in order to prepare them to take advantage of the new 3.0 features. Please read this migration document carefully, as it outlines in detail the required migration steps. It also calls out areas of consideration depending on the degree to which you've customized your Broadleaf Commerce installation. Use these instructions at your own risk. Make sure to backup your data before attempting any migration and always test in a development environment before executing in production.

Migration Steps

Maven updates

Item: Update the root pom.xml (sample file)

  1. While it may be introduced again in the future, the combined module is not currently supported in 3.0.

    • In the root pom.xml, remove the line <module>combined</module> from the "modules" element.
  2. Change the blc.version element to 3.0.0-SNAPSHOT

    <blc.version>3.0.0-SNAPSHOT</blc.version>

  3. Remove the gwt.version element (phased out)

    <gwt.version>2.4.0</gwt.version>

  4. If not present already, add a public snapshots repository to retrieve BLC snapshot builds.

    <repositories>
        <repository>
            <id>public snapshots</id>
            <name>public snapshots</name>
            <url>http://nexus.broadleafcommerce.org/nexus/content/repositories/snapshots/</url>
        </repository>
    </repositories>
    
  5. Update jrebel plugin dependency

    • change all instances of <artifactId>javarebel-maven-plugin</artifactId> to <artifactId>jrebel-maven-plugin</artifactId>
    • change the jrebel plugin version to 1.1.3
  6. Remove gwt maven plugin config (phased out)

    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>gwt-maven-plugin</artifactId>
        <version>${gwt.version}</version>
    </plugin>
    
  7. Remove the following unwanted, or unnecessary dependency elements

    • groupId: com.google.gwt / artifactId: gwt-user
    • groupId: org.hibernate / artifactId: hibernate-validator-annotation-processor
    • groupId: javax.validation / artifactId: validation-api

Item: Update admin/pom.xml (sample file)

  1. Remove the following unwanted, or unnecessary plugins

    • groupId: org.apache.maven.plugins / artifactId: maven-source-plugin
    • groupId: org.codehaus.mojo / artifactId: gwt-maven-plugin
    • groupId: org.apache.maven.plugins / artifactId: maven-clean-plugin
  2. Remove the following unwanted, or unnecessary profiles

    • id: gwt-jrebel
    • id: full-clean
  3. Remove the following unwanted, or unnecessary dependency elements

    • groupId: org.hibernate / artifactId: hibernate-validator-annotation-processor
    • groupId: javax.validation / artifactId: validation-api
  4. Update jrebel plugin dependency

    • change all instances of <artifactId>javarebel-maven-plugin</artifactId> to <artifactId>jrebel-maven-plugin</artifactId>
  5. Add additional lines to the configuration block of the jetty-maven-plugin:

    <webAppConfig>
        <allowDuplicateFragmentNames>true</allowDuplicateFragmentNames>
    </webAppConfig>
    

Item: Update site/pom.xml (sample file)

  1. Update jrebel plugin dependency

    • change all instances of <artifactId>javarebel-maven-plugin</artifactId> to <artifactId>jrebel-maven-plugin</artifactId>
  2. Add additional lines to the configuration block of the jetty-maven-plugin:

    <webAppConfig>
        <allowDuplicateFragmentNames>true</allowDuplicateFragmentNames>
    </webAppConfig>
    

Item: Update core/pom.xml (sample file)

  1. Update jrebel plugin dependency
    • change all instances of <artifactId>javarebel-maven-plugin</artifactId> to <artifactId>jrebel-maven-plugin</artifactId>

Web.xml updates

Item: Update site/src/main/webapp/WEB-INF/web.xml (sample file)

  1. Add the filter application context

    • add /WEB-INF/applicationContext-filter.xml immediately before /WEB-INF/applicationContext.xml in the <param-value> element for <param-name>patchConfigLocation</param-name>
  2. Remove the following <filter> definitions, as they are now declared in applicationContext-filter.xml

    • filter-name: entityManagerInViewFilter
    • filter-name: blRequestFilter
    • filter-name: blUrlHandlerFilter
  3. Remove the following <filter-mapping> definitions as well

    • filter-name: entityManagerInViewFilter
    • filter-name: blRequestFilter
    • filter-name: blUrlHandlerFilter
  4. Remove the following line from the contextConfigLocation list in the main servlet:
    classpath:/bl-framework-web-applicationContext-servlet.xml


Item: Update admin/src/main/webapp/WEB-INF/web.xml (sample file)

  1. Add the filter application context

    • add /WEB-INF/applicationContext-admin-filter.xml immediately before /WEB-INF/applicationContext-admin.xml in the <param-value> element for <param-name>patchConfigLocation</param-name>
  2. Remove the following <filter> definitions, as they are now declared in applicationContext-filter.xml

    • filter-name: entityManagerInViewFilter
    • filter-name: blAdminSandBoxFilter
    • filter-name: blPrecompressedArtifactsFilter
  3. Remove the following <filter-mapping>. definitions as well

    • filter-name: entityManagerInViewFilter
    • filter-name: blAdminSandBoxFilter
    • filter-name: blPrecompressedArtifactsFilter
  4. Remove the following unwanted <servlet> and <servlet-mapping> elements

    • servlet-name: remoteLogging
  5. Remove "admin.html" as a <welcome-file> element

  6. Add the following listener if it's not already present

    <listener>
        <listener-class>
             org.springframework.web.context.request.RequestContextListener
        </listener-class>
    </listener>
    

Application Context Updates

Item: Update all applicationContext*.xml files

  1. Look in site/src/main/webapp/WEB-INF, admin/src/main/webapp/WEB-INF and core/src/main/resources

  2. Change all spring schemaLocation attribute values to point to 3.2 (e.g. spring-jee-3.1.xsd should point to spring-jee-3.2.xsd)

    • Except for spring-security-3.1.xsd, which should be left at version 3.1

Item: Update site/src/main/webapp/WEB-INF/applicationContext.xml (sample file)

  1. Add externalized string support by including the "messageSource" bean:

    <bean id="messageSource" class="org.broadleafcommerce.common.util.BroadleafMergeResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>classpath:messages</value>
            </list>
        </property>
    </bean>
    
  2. Add image thumbnail support:

    <bean id="blStaticMapNamedOperationComponent" class="org.broadleafcommerce.cms.file.service.operation.StaticMapNamedOperationComponent">
        <property name="namedOperations">
            <map>
                <entry key="browse">
                    <map>
                        <entry key="resize-width-amount" value="400"/>
                        <entry key="resize-height-amount" value="400"/>
                        <entry key="resize-high-quality" value="false"/>
                        <entry key="resize-maintain-aspect-ratio" value="true"/>
                        <entry key="resize-reduce-only" value="true"/>
                    </map>
                </entry>
                <entry key="thumbnail">
                    <map>
                        <entry key="resize-width-amount" value="60"/>
                        <entry key="resize-height-amount" value="60"/>
                        <entry key="resize-high-quality" value="false"/>
                        <entry key="resize-maintain-aspect-ratio" value="true"/>
                        <entry key="resize-reduce-only" value="true"/>
                    </map>
                </entry>
            </map>
        </property>
    </bean>
    

Item: Update site/src/main/webapp/WEB-INF/applicationContext-security.xml (sample file)

  1. Remove the <sec:custom-filter ref="blCartStateFilter" before="ANONYMOUS_FILTER"/> element

  2. Add the following filters in the <sec:http> element:

    <sec:custom-filter ref="blPreSecurityFilterChain" before="CHANNEL_FILTER"/>
    <sec:custom-filter ref="blPostSecurityFilterChain" after="SWITCH_USER_FILTER"/>
    

Item: Update site/src/main/webapp/WEB-INF/applicationContext-servlet.xml (sample file)

  1. Add a new bean to <mvc:interceptors>:

    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
        <property name="paramName" value="blLocaleCode"/>
    </bean>
    
  2. Add a new bean for "localeResolver":

    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
        <property name="defaultLocale" value="en"/>
    </bean>
    
  3. Remove the <mvc:resources> elements for location="/js/" and location="/css/"

  4. Add new beans for the bundling-capable resource handler:

    <bean id="blJsResources" class="org.broadleafcommerce.common.web.resource.BroadleafResourceHttpRequestHandler">
        <property name="locations">
            <list>
                <value>/js/</value>
                <value>classpath:/common_js/</value>
            </list>
        </property>
    </bean>
    
    <bean id="blCssResources" class="org.broadleafcommerce.common.web.resource.BroadleafResourceHttpRequestHandler">
        <property name="locations">
            <list>
                <value>/css/</value>
            </list>
        </property>
    </bean>
    
    <!-- Map various location URLs to our resource handlers -->
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="order" value="-10" />
        <property name="mappings">
            <props>
                <prop key="/js/**">blJsResources</prop>
                <prop key="/css/**">blCssResources</prop>
            </props>
        </property>
    </bean>
    
  5. Remove beans with ids "resourceBundleExtensionPoint" and "messageSource"

  6. Add the following component scans:

    <context:component-scan base-package="org.broadleafcommerce.common.web"/>
    <context:component-scan base-package="org.broadleafcommerce.core.web"/> 
    <context:component-scan base-package="org.broadleafcommerce.profile.web"/>
    

Item: Add the new site/src/main/webapp/WEB-INF/applicationContext-filter.xml file

  1. Download from https://github.com/BroadleafCommerce/DemoSite/blob/broadleaf-3.0.0-GA/site/src/main/webapp/WEB-INF/applicationContext-filter.xml

Item: Update admin/src/main/webapp/WEB-INF/applicationContext-admin.xml (sample file)

  1. Add externalized string support by including the "messageSource" bean:

    <bean id="messageSource" class="org.broadleafcommerce.common.util.BroadleafMergeResourceBundleMessageSource">
        <property name="useCodeAsDefaultMessage" value="${messages.useCodeAsDefaultMessage}" />
        <property name="cacheSeconds" value="${messages.cacheSeconds}" />
        <property name="basenames">
            <list>
                <value>classpath:messages-admin</value>
            </list>
        </property>
    </bean>
    
  2. Add additionally required bundle files to the JavaScript bundle:

    <bean id="blResourceBundlingService" class="org.broadleafcommerce.common.resource.service.ResourceBundlingServiceImpl">
        <property name="additionalBundleFiles">
            <map>
                <entry key="admin.js">
                    <list>
                        <value>admin/catalog/product.js</value>
                        <value>admin/catalog/offer.js</value>
                        <value>admin/catalog/category.js</value>
                    </list>
                </entry>
            </map>
        </property>
    </bean>
    

Item: Update admin/src/main/webapp/WEB-INF/applicationContext-admin-security.xml (sample file)

  1. Replace <sec:http> elements for ignoring security for static elements and "forgot password" flows. Use the following:

    <sec:http pattern="/**/*.css" security="none" />
    <sec:http pattern="/**/*.js" security="none" />
    <sec:http pattern="/img/**" security="none" />
    <sec:http pattern="/favicon.ico" security="none" />
    <sec:http pattern="/robots.txt" security="none" />
    <sec:http pattern="/login" security="none" />
    <sec:http pattern="/forgotUsername" security="none" />
    <sec:http pattern="/forgotPassword" security="none" />
    <sec:http pattern="/changePassword" security="none" />
    <sec:http pattern="/resetPassword" security="none" />
    <sec:http pattern="/sendResetPassword" security="none" />
    
  2. Update the main <sec:http> element to include the entry-point-ref attribute:

    <sec:http auto-config="false" authentication-manager-ref="blAdminAuthenticationManager" entry-point-ref="adminAuthenticationEntryPoint">
    
  3. Update the main <sec:http> element filters to include the following:

    <sec:custom-filter ref="blPreSecurityFilterChain" before="CHANNEL_FILTER"/>
    <sec:custom-filter ref="blCsrfFilter" before="FORM_LOGIN_FILTER"/>
    <sec:custom-filter ref="blPostSecurityFilterChain" after="SWITCH_USER_FILTER"/>
    
  4. Replace the <sec:form-login> element with the following. The login-page and login-processing-url attributes have changed:

    <sec:form-login
        authentication-success-handler-ref="blAdminAuthenticationSuccessHandler"
        authentication-failure-handler-ref="blAdminAuthenticationFailureHandler"
        login-processing-url="/login_admin_post" />
    
  5. Replace the <sec:logout> element with the following. The logout-url and logout-success-url attributes have changed.

    <sec:logout invalidate-session="true" logout-url="/adminLogout.htm" logout-success-url="/login"/>
    
  6. Add an "adminAuthenticationEntryPoint" bean:

    <bean id="adminAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
        <constructor-arg value="/login"/>
        <property name="useForward" value="true"/>
    </bean>
    
  7. Update the <sec:intercept-url> elements for "blAdminFilterSecurityInterceptor" to the following. The patterns have changed.

    <sec:intercept-url pattern="/**/*" access="PERMISSION_OTHER_DEFAULT" />
    <sec:intercept-url pattern="/*" access="PERMISSION_OTHER_DEFAULT" />
    
  8. Replace the "blAdminAuthenticationFailureHandler" bean with the following.

    <bean id="blAdminAuthenticationFailureHandler" class="org.broadleafcommerce.openadmin.security.BroadleafAdminAuthenticationFailureHandler">
        <constructor-arg value="/login?login_error=true" />
    </bean>
    
  9. Replace the "blAdminAuthenticationSuccessHandler" bean with the following.

    <bean id="blAdminAuthenticationSuccessHandler" class="org.broadleafcommerce.openadmin.security.BroadleafAdminAuthenticationSuccessHandler">
        <property name="defaultTargetUrl" value="/loginSuccess"/>
        <property name="alwaysUseDefaultTargetUrl" value="false"/>
    </bean>
    
  10. Add the following bean

    <bean id="blCsrfFilter" class="org.broadleafcommerce.common.security.handler.CsrfFilter" />
    
  11. Change the <sec:password-encoder> bean to utilize the blAdminPasswordEncoder bean:

    <sec:password-encoder ref="blAdminPasswordEncoder" />
    

Item: Replace admin/src/main/webapp/WEB-INF/applicationContext-servlet-admin.xml

  1. Download from https://github.com/BroadleafCommerce/DemoSite/blob/broadleaf-3.0.0-GA/admin/src/main/webapp/WEB-INF/applicationContext-servlet-admin.xml

  2. Replace admin/src/main/webapp/WEB-INF/applicationContext-servlet-admin.xml with the downloaded file


Item: Add the new admin/src/main/webapp/WEB-INF/applicationContext-admin-filter.xml file

  1. Download from https://github.com/BroadleafCommerce/DemoSite/blob/broadleaf-3.0.0-GA/admin/src/main/webapp/WEB-INF/applicationContext-admin-filter.xml

Other Updates

Item: A custom AdminLoginController (extends BroadleafAdminLoginController) is no longer required. Remove such a class if you've implemented one.

Item: Update Solr configuration (if using Solr search)

  1. Update site/resources/schema.xml

  2. If you have customized Solr indexing configuration, then review your changes before performing any update here

  3. Replace the <fields> element with the following:

    <fields>
        <field name="namespace" type="string" indexed="true" stored="false" />
        <field name="id" type="string" indexed="true" stored="true" />
        <field name="productId" type="long" indexed="true" stored="true" />
        <field name="category" type="long" indexed="true" stored="false" multiValued="true" />
        <field name="explicitCategory" type="long" indexed="true" stored="false" multiValued="true" />
        <field name="searchable" type="text_general" indexed="true" stored="false" />
        <dynamicField name="*_searchable" type="text_general" indexed="true" stored="false" />
    
        <dynamicField name="*_i" type="int" indexed="true" stored="false" />
        <dynamicField name="*_is" type="int" indexed="true" stored="false" multiValued="true" />
        <dynamicField name="*_s" type="string" indexed="true" stored="false" />
        <dynamicField name="*_ss" type="string" indexed="true" stored="false" multiValued="true" />
        <dynamicField name="*_l" type="long" indexed="true" stored="false" />
        <dynamicField name="*_ls" type="long" indexed="true" stored="false" multiValued="true" />
        <dynamicField name="*_t" type="text_general" indexed="true" stored="false" />
        <dynamicField name="*_txt" type="text_general" indexed="true" stored="false" multiValued="true" />
        <dynamicField name="*_b" type="boolean" indexed="true" stored="false" />
        <dynamicField name="*_bs" type="boolean" indexed="true" stored="false" multiValued="true" />
        <dynamicField name="*_d" type="double" indexed="true" stored="false" />
        <dynamicField name="*_ds" type="double" indexed="true" stored="false" multiValued="true" />
        <dynamicField name="*_p" type="double" indexed="true" stored="false" />
    
        <dynamicField name="*_dt" type="date" indexed="true" stored="false" />
        <dynamicField name="*_dts" type="date" indexed="true" stored="false" multiValued="true" />
    
        <!-- some trie-coded dynamic fields for faster range queries -->
        <dynamicField name="*_ti" type="tint" indexed="true" stored="false" />
        <dynamicField name="*_tl" type="tlong" indexed="true" stored="false" />
        <dynamicField name="*_td" type="tdouble" indexed="true" stored="false" />
        <dynamicField name="*_tdt" type="tdate" indexed="true" stored="false" />
    </fields>
    

Data Migration

Item: Update build.properties

  1. Add database connection information to build.properties (change to fit your environment)

    ant.blPU.url=jdbc:mysql://localhost:3306/broadleafcommerce_20
    ant.blPU.userName=root
    ant.blPU.password=
    ant.blPU.driverClassName=com.mysql.jdbc.Driver
    
    ant.blSecurePU.url=jdbc:mysql://localhost:3306/broadleafcommerce_20
    ant.blSecurePU.userName=root
    ant.blSecurePU.password=
    ant.blSecurePU.driverClassName=com.mysql.jdbc.Driver
    
    ant.blCMSStorage.url=jdbc:mysql://localhost:3306/broadleafcommerce_20
    ant.blCMSStorage.userName=root
    ant.blCMSStorage.password=
    ant.blCMSStorage.driverClassName=com.mysql.jdbc.Driver
    
  2. Make sure the ant.hibernate.sql.ddl.dialect value in build.properties is the correct dialect for your target schema. Change if required.


Item: Replace the build-sql task in site/build.xml

  1. Delete the <target name="build-sql"> element, as it is out-of-date

  2. Add the following to build.xml

    <target name="build-create-sql">
        <!--
            You will need to run a mvn install on your project before attempting to execute this task.
            Also, you will likely need to assign additional heap space to your ANT process. A setting
            of -XX:MaxPermSize=256M -Xmx512M should be sufficient.
    
            This can be done by populating the 'ANT_OPTS' environment variable:
                export ANT_OPTS=-XX:MaxPermSize=256M -Xmx512M
            which will ensure those settings for all ant processes. Alternatively you could use JAVA_OPTS which is for
            the global JVM and will effect all Java processes.
        -->
        <mkdir dir="target/sql/create"/>
        <artifact:pom id="myPom" file="pom.xml" />
        <artifact:dependencies filesetId="pomDeps" pomRefId="myPom" useScope="compile" />
        <property name="baseTarget" location="target/${myPom.build.finalName}/WEB-INF"/>
        <fileset id="libDir" dir="${baseTarget}/lib"/>
        <path id="build.runtime.classpath">
            <!--There are some additional libraries needed at compile time that are not included
                in WEB-INF/lib - find those libraries via a difference algorithm-->
            <restrict>
                <difference>
                    <fileset refid="pomDeps" />
                    <intersect>
                        <fileset refid="pomDeps" />
                        <fileset refid="libDir" />
                    </intersect>
                </difference>
                <rsel:not>
                    <rsel:name name="**/*.pom" />
                </rsel:not>
            </restrict>
            <!--Add the lib directory to get all the dependencies required for the demo app-->
            <fileset refid="libDir"/>
            <dirset dir="src/main/resources" />
            <!--Add the classes directory in the war project, if required-->
            <!--<pathelement location="${baseTarget}/classes"/>-->
        </path>
        <!--If the war project does not contain custom entities (best practice), then it is not necessary to include application context from the WEB-INF directory-->
        <!--<property name="my.app.context" location="src/main/webapp/WEB-INF/applicationContext.xml"/>-->
        <taskdef name="hibernatetool" classname="org.broadleafcommerce.common.util.sql.HibernateToolTask" classpathref="build.runtime.classpath"/>
        <hibernatetool destDir="target/sql/create" combinePersistenceUnits="false" refineFileNames="true">
            <!--add in additional persistence configuration related to the cms -->
            <classPathApplicationContext path="bl-cms-contentClient-applicationContext.xml"/>
            <classPathApplicationContext path="bl-open-admin-contentClient-applicationContext.xml"/>
            <!--add in additional persistence configuration for our core -->
            <classPathApplicationContext path="applicationContext.xml"/>
            <!--see description for my.app.context above -->
            <fileSystemApplicationContext path="src/main/webapp/WEB-INF/applicationContext.xml"/>
            <classPathApplicationContext path="bl-fake-applicationContext-ant.xml"/>
            <!--select the dialects and persistence units to export-->
            <jpaconfiguration persistenceUnit="blPU" dialect="${ant.hibernate.sql.ddl.dialect}" />
            <jpaconfiguration persistenceUnit="blSecurePU" dialect="${ant.hibernate.sql.ddl.dialect}" />
            <jpaconfiguration persistenceUnit="blCMSStorage" dialect="${ant.hibernate.sql.ddl.dialect}" />
            <!--other required elements-->
            <classpath refid="build.runtime.classpath" />
            <hbm2ddl export="false" update="false" create="true"/>
        </hibernatetool>
    </target>
    
    <target name="build-update-sql">
        <!--
            You will need to run a mvn install on your project before attempting to execute this task.
            Also, you will likely need to assign additional heap space to your ANT process. A setting
            of -XX:MaxPermSize=256M -Xmx512M should be sufficient.
    
            This can be done by populating the 'ANT_OPTS' environment variable:
                export ANT_OPTS=-XX:MaxPermSize=256M -Xmx512M
            which will ensure those settings for all ant processes. Alternatively you could use JAVA_OPTS which is for
            the global JVM and will effect all Java processes.
        -->
        <mkdir dir="target/sql/update"/>
        <artifact:pom id="myPom" file="pom.xml" />
        <artifact:dependencies filesetId="pomDeps" pomRefId="myPom" useScope="compile" />
        <property name="baseTarget" location="target/${myPom.build.finalName}/WEB-INF"/>
        <fileset id="libDir" dir="${baseTarget}/lib"/>
        <path id="build.runtime.classpath">
            <!--There are some additional libraries needed at compile time that are not included
                in WEB-INF/lib - find those libraries via a difference algorithm-->
            <restrict>
                <difference>
                    <fileset refid="pomDeps" />
                    <intersect>
                        <fileset refid="pomDeps" />
                        <fileset refid="libDir" />
                    </intersect>
                </difference>
                <rsel:not>
                    <rsel:name name="**/*.pom" />
                </rsel:not>
            </restrict>
            <!--Add the lib directory to get all the dependencies required for the demo app-->
            <fileset refid="libDir"/>
            <dirset dir="src/main/resources" />
            <!--Add the classes directory in the war project, if required-->
            <!--<pathelement location="${baseTarget}/classes"/>-->
        </path>
        <!--If the war project does not contain custom entities (best practice), then it is not necessary to include application context from the WEB-INF directory-->
        <!--<property name="my.app.context" location="src/main/webapp/WEB-INF/applicationContext.xml"/>-->
        <taskdef name="hibernatetool" classname="org.broadleafcommerce.common.util.sql.HibernateToolTask" classpathref="build.runtime.classpath" />
        <hibernatetool destDir="target/sql/update" combinePersistenceUnits="false" refineFileNames="true">
            <!--add in additional persistence configuration related to the cms -->
            <classPathApplicationContext path="bl-cms-contentClient-applicationContext.xml"/>
            <classPathApplicationContext path="bl-open-admin-contentClient-applicationContext.xml"/>
            <!--add in additional persistence configuration for our core -->
            <classPathApplicationContext path="applicationContext.xml"/>
            <!--see description for my.app.context above -->
            <fileSystemApplicationContext path="src/main/webapp/WEB-INF/applicationContext.xml"/>
            <classPathApplicationContext path="bl-fake-applicationContext-ant.xml"/>
            <!--select the dialects and persistence units to export-->
            <jpaconfiguration persistenceUnit="blPU" dialect="${ant.hibernate.sql.ddl.dialect}" 
                url="${ant.blPU.url}" 
                userName="${ant.blPU.userName}" 
                password="${ant.blPU.password}" 
                driverClassName="${ant.blPU.driverClassName}"/>
            <jpaconfiguration persistenceUnit="blSecurePU" dialect="${ant.hibernate.sql.ddl.dialect}" 
                url="${ant.blSecurePU.url}" 
                userName="${ant.blSecurePU.userName}" 
                password="${ant.blSecurePU.password}" 
                driverClassName="${ant.blSecurePU.driverClassName}"/>
            <jpaconfiguration persistenceUnit="blCMSStorage" dialect="${ant.hibernate.sql.ddl.dialect}" 
                url="${ant.blCMSStorage.url}" 
                userName="${ant.blCMSStorage.userName}" 
                password="${ant.blCMSStorage.password}" 
                driverClassName="${ant.blCMSStorage.driverClassName}"/>
            <!--other required elements-->
            <classpath refid="build.runtime.classpath" />
            <hbm2ddl export="false" update="true" create="false"/>
        </hibernatetool>
    </target>
    

Item: Update your current 2.1 database schema to be 3.0 compliant

  1. Via ANT, execute the "build-update-sql" task in site/build.xml (will take a few minutes to run)
    • This task should launch a lightweight version of Broadleaf's domain and your domain extensions
    • A comparison is performed against this combined domain and the target schema
    • The result of this comparison is an update sql file that can be run against your existing schema to alter its structure to be 3.0 compliant
    • Open the emitted update sql file: site/target/sql/update/*Dialect_blPU.sql
    • Execute the contents of this sql file against your target schema using your favorite sql execution environment

Item: Update admin permissions

  1. The most straightforward approach is to remove old information and repopulate

    • If you've done a lot of role customization for admin users, then this section will require some diligence, as you will need to manually rebuild your associations between roles and permissions. You may want to record the permissions you have associated with each role (see your BLC_ADMIN_ROLE_PERMISSION_XREF table) so that you can recreate these with the repopulated information.
    • Refer to the following table of standard roles and required permissions in 3.0. This can be used as a guide.
    Role Name Permission Name
    ROLE_CONTENT_APPROVER PERMISSION_ALL_APPROVER_SANDBOX
    ROLE_CONTENT_APPROVER PERMISSION_ALL_STRUCTURED_CONTENT
    ROLE_CONTENT_APPROVER PERMISSION_ALL_ASSET
    ROLE_CONTENT_APPROVER PERMISSION_ALL_PAGE
    ROLE_CONTENT_APPROVER PERMISSION_OTHER_DEFAULT
    ROLE_CONTENT_EDITOR PERMISSION_ALL_USER_SANDBOX
    ROLE_CONTENT_EDITOR PERMISSION_ALL_STRUCTURED_CONTENT
    ROLE_CONTENT_EDITOR PERMISSION_ALL_ASSET
    ROLE_CONTENT_EDITOR PERMISSION_ALL_PAGE
    ROLE_CONTENT_EDITOR PERMISSION_OTHER_DEFAULT
    ROLE_CUSTOMER_SERVICE_REP PERMISSION_ALL_CUSTOMER
    ROLE_CUSTOMER_SERVICE_REP PERMISSION_ALL_ORDER_ITEM
    ROLE_CUSTOMER_SERVICE_REP PERMISSION_ALL_FULFILLMENT_GROUP
    ROLE_CUSTOMER_SERVICE_REP PERMISSION_ALL_ORDER
    ROLE_CUSTOMER_SERVICE_REP PERMISSION_OTHER_DEFAULT
    ROLE_PROMOTION_MANAGER PERMISSION_ALL_PROMOTION
    ROLE_PROMOTION_MANAGER PERMISSION_OTHER_DEFAULT
    ROLE_MERCHANDISE_MANAGER PERMISSION_ALL_CURRENCY
    ROLE_MERCHANDISE_MANAGER PERMISSION_ALL_SEARCHFACET
    ROLE_MERCHANDISE_MANAGER PERMISSION_ALL_ASSET
    ROLE_MERCHANDISE_MANAGER PERMISSION_ALL_SKU
    ROLE_MERCHANDISE_MANAGER PERMISSION_ALL_PRODUCT_OPTION
    ROLE_MERCHANDISE_MANAGER PERMISSION_ALL_PRODUCT
    ROLE_MERCHANDISE_MANAGER PERMISSION_ALL_CATEGORY
    ROLE_MERCHANDISE_MANAGER PERMISSION_OTHER_DEFAULT
    ROLE_ADMIN PERMISSION_ALL_MODULECONFIGURATION
    ROLE_ADMIN PERMISSION_ALL_CURRENCY
    ROLE_ADMIN PERMISSION_ALL_SEARCHFACET
    ROLE_ADMIN PERMISSION_ALL_SEARCHREDIRECT
    ROLE_ADMIN PERMISSION_ALL_URLHANDLER
    ROLE_ADMIN PERMISSION_ALL_ADMIN_USER
    ROLE_ADMIN PERMISSION_ALL_APPROVER_SANDBOX
    ROLE_ADMIN PERMISSION_ALL_USER_SANDBOX
    ROLE_ADMIN PERMISSION_ALL_STRUCTURED_CONTENT
    ROLE_ADMIN PERMISSION_ALL_ASSET
    ROLE_ADMIN PERMISSION_ALL_PAGE
    ROLE_ADMIN PERMISSION_ALL_CUSTOMER
    ROLE_ADMIN PERMISSION_ALL_ORDER_ITEM
    ROLE_ADMIN PERMISSION_ALL_FULFILLMENT_GROUP
    ROLE_ADMIN PERMISSION_ALL_ORDER
    ROLE_ADMIN PERMISSION_ALL_PROMOTION
    ROLE_ADMIN PERMISSION_ALL_SKU
    ROLE_ADMIN PERMISSION_ALL_PRODUCT_OPTION
    ROLE_ADMIN PERMISSION_ALL_PRODUCT
    ROLE_ADMIN PERMISSION_ALL_CATEGORY
    ROLE_ADMIN PERMISSION_OTHER_DEFAULT
  2. Clear out the BLC_ADMIN_ROLE_PERMISSION_XREF table to avoid constraint violations during the next steps

  3. Clear out the BLC_ADMIN_PERMISSION_ENTITY table so that new values can be imported

  4. Clear out the BLC_ADMIN_PERMISSION table so that new values can be imported

  5. Download the re-population sql: https://github.com/BroadleafCommerce/BroadleafCommerce/blob/broadleaf-3.0.0-GA/core/broadleaf-framework/src/main/resources/config/bc/sql/load_admin_permissions.sql

  6. Execute the re-population sql against your database using your favorite sql execution environment

  7. Rebuild your BLC_ADMIN_ROLE_PERMISSION_XREF table mapping your custom roles to the appropriate permissions

    • If you have NOT altered any roles and took advantage of the roles from the 2.1 demo starter project, you can execute the following in your favorite sql execution environment to rebuild the BLC_ADMIN_ROLE_PERMISSION_XREF table.
    -- Super User
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-1);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-6);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-11);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-16);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-21);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-26);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-31);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-36);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-41);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-46);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-51);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-56);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-61);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-62);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-63);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-68);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-73);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-78);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-83);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-88);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (1,-93);
    
    -- Merchandiser
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (2,-1);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (2,-6);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (2,-11);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (2,-16);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (2,-21);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (2,-56);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (2,-83);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (2,-88);
    
    -- Promotions
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (3,-1);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (3,-26);
    
    -- CSR
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (4,-1);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (4,-31);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (4,-36);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (4,-41);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (4,-46);
    
    -- CMS Editor
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (5,-1);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (5,-51);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (5,-56);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (5,-61);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (5,-62);
    
    -- CMS Approver
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (6,-1);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (6,-51);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (6,-56);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (6,-61);
    INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (6,-63);
    

Item: Add data for admin sections and modules

  1. Download the population sql: https://github.com/BroadleafCommerce/BroadleafCommerce/blob/broadleaf-3.0.0-GA/core/broadleaf-framework/src/main/resources/config/bc/sql/load_admin_menu.sql

  2. Execute the population sql against your database using your favorite sql execution environment


Item: Address Hibernate 4 change for boolean fields from Bit to TinyInt (applies to MySql)

  1. If you are using MySql as your database platform, you'll need to check how boolean fields are represented. Review the structure of your current BLC_ADDRESS table. If the IS_ACTIVE column is of type BIT, then you are using the old way of representing boolean fields in MySql. If the type is TINYINT, then you can ignore this item.

  2. If your boolean columns are represented as BIT, then you have 2 choices for Broadleaf 3.0 compatibility:

    • You can convert all boolean field columns in your Broadleaf database schema from BIT to TINYINT, OR
    • You can use org.broadleafcommerce.common.dialect.Broadleaf2CompatibilityMySQL5InnoDBDialect as your Hibernate dialect (this custom dialect takes care of referencing boolean fields as type BIT, rather than TINYINT)
  3. There are no known issues with PostgreSql, Sql Server or Oracle.


Item: Make sure locale settings are up-to-date

  1. Review the contents of the BLC_LOCALE table. One of the locales should be marked as default.

  2. Make sure the default locale is your desired locale, as this can impact price display on your site

  3. For example, if en is the default locale, you may want to add a new locale with code en_US for US English and make it the default instead.


Item: Make sure existing orders are compatible

  1. Add a value to the LOCALE_CODE column for all orders in the BLC_ORDER table. For example, use en_US for US English.

Item: Property file updates

  1. Remove the use.jrebel.compatibility.mode property as it is no longer used.
  2. Add thymeleaf.view.resolver.cache=true to common-shared.properties and thymeleaf.view.resolver.cache=false to development-shared.properties

Considerations

Admin Customization Considerations (If your current implementation has admin customizations)

  1. GWT has been phased out and is no longer supported for admin UI/functionality customization.
  2. Logical portions of the admin are broken up into Modules, which themselves contains sections.
  3. Modules are represented in the BLC_ADMIN_MODULE table and sections are represented in the BLC_ADMIN_SECTION table.
  4. @AdminPresentation annotations in the Broadleaf domain classes support most of the functionality observed in the admin.
  5. For simple extended properties, it's possible that you're entity extensions may work as they are in the new admin without any additional @AdminPresentation annotation tweaking.
  6. For collection/map fields in your entity extensions, you will need to use one of the admin presentation collection annotations. Refer to the source code for ProductImpl for a variety of concrete usage examples.
  7. Spring MVC is employed to drive most of the plumbing - specialized controllers can be used to achieve specific results (e.g. see AdminOrderController in the Broadleaf source).

Order Pricing Considerations

  1. In previous releases, it was possible for order items to be split in the order when promotions were applied. This generally occurred as the result of a Buy-One-Get-One-Free promotion where only part of the total quantity for an item qualified for a discount. In such a case, a new discounted Order Item was created with the smaller quantity and the quantity for the regularly priced item was decremented - essentially "splitting" the item.
  2. The "splitting" practice was error prone, as various parts of the order had to be update to compensate for the split (e.g. fulfillment group items had to be updated).
  3. In version 3.0, we have done away with the Order Item splitting concept in favor of OrderItemPriceDetails.
  4. OrderItemPriceDetails allows a single order item to have multiple prices for multiple quantities. This solves the requirement for discounting several of an order item's quantity, while not changing the quantity of the order item itself.
  5. As a result, a call to OrderItem.getPrice() now returns an average of the price details for an item.
  6. Depending on how order item pricing is displayed on your site, this change could have an impact on what your users see and your site should be thoroughly tested after the upgrade as a result.

Offer Considerations

  1. The MVEL generated for offers in version 2.1 may be incompatible with the new 3.0 rule builder UI.
  2. Incompatible rules will still function in the system, but will be displayed in the admin page as immutable,raw MVEL.
  3. If you wish to change the rules for an incompatible offer, you'll need to disable the incompatible offer and create a new offer that matches your desired rules and configuration.

Translation Considerations (if your site requires multiple language support)

  1. Broadleaf 3.0 offers new field-level translation in the admin (denoted by a globe icon - see product name for an example).
  2. To take advantage of this new translation service, consider moving your catalog translations to the BLC_TRANSLATION table.
  3. Take a look at the 3.0 demo site BLC_TRANSLATION data for examples. (Sample translation data)

Heat Clinic Considerations

Please note that this migration documentation is to be used as a guide in migrating any generic Broadleaf Commerce application to version 3.0. We do not cover things that we might have changed in our starter Heat Clinic project, such as miscellaneous CSS updates, etc. For example, to take advantage of the PhoneImpl Java class, we changed the Heat Clinic checkout's billingInfoForm.html. These kinds of specialized changes in our sample application are not covered as part of this guide.

If you would like to see an absolutely comprehensive list of all changes that were made to our sample application between 2.1 and 3.0, you can utilize this GitHub branch compare link.