Broadleaf 3.1.0-GA
3.1.0-GA includes a ton of awesome features, bug fixes and enhancements. Here are the major feature highlights of this release.
Friendly REST exceptions
There is a new class to help build XML/JSON responses into exceptions that might occur in your REST APIs with BroadleafWebServicesException
s. Usage of this class hs through a static invocation to build()
. An example is in the addOfferCode
method of CartEndpoint
:
public OrderWrapper addOfferCode(HttpServletRequest request,
String promoCode,
boolean priceOrder) {
// code removed
OfferCode offerCode = offerService.lookupOfferCodeByCode(promoCode);
if (offerCode == null) {
throw BroadleafWebServicesException.build(Response.Status.NOT_FOUND.getStatusCode())
.addMessage(BroadleafWebServicesException.PROMO_CODE_INVALID, promoCode);
}
// etc...
}
The exception builder takes in the HTTP status code (in this case a 404) and then also adds a not-found message. This exception is later parsed by the BroadleafRestExceptionMapper
. This exception mapper should already be hooked up but if not, include it as a bean in your applicationContext-rest-api.xml
:
<bean class="org.broadleafcommerce.core.web.api.BroadleafRestExceptionMapper" scope="singleton"/>
Note: error messages are translated via Spring's message i18n property resolution. The above case also uses a parameterized message with the promo code that was not found
Site Maps
There is new functionality to configure a site map generator to scan through your existing Category, Product and Page domain and output a sitemap file for web crawlers. Documentation on how to set this up are in SEO. One additional configuration step is to add a new controller to respond to requests for a site map:
@Controller
public class SiteMapController extends BroadleafSiteMapController {
@RequestMapping(value = { "/sitemap*.xml", "sitemap*.gz" })
@ResponseBody
public FileSystemResource retrieveSiteMapIndex(HttpServletRequest request, HttpServletResponse response)
throws IOException {
return super.retrieveSiteMapFile(request, response);
}
}
You also want to notify crawlers via robots.txt
about your site map. You can add this functionality with a robots controller:
@Controller
public class RobotsController extends BroadleafRobotsController {
@RequestMapping(value = { "/robots.txt" })
@ResponseBody
public String getRobotsFile(HttpServletRequest request, HttpServletResponse response) {
return super.getRobotsFile(request, response);
}
}
Payment Domain Refactor
See the Payment section for more information on what this looks like and 3.0 to 3.1 Migration if you are upgrading from 3.0
Cart and Customer Cleanup Jobs
You can now configure a Quartz job to remove old IN_PROCESS Carts and non-registered users from your system. Below is an example configuration that will delete all IN_PROCESS
Orders (carts) that are older than 30 days (2592000 seconds):
<bean id="purgeCartConfig" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
<entry key="SECONDS_OLD" value="2592000"/>
<entry key="STATUS" value="IN_PROCESS"/>
</map>
</property>
</bean>
<bean id="purgeCartJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="blResourcePurgeService" />
<property name="targetMethod" value="purgeCarts" />
<property name="arguments">
<list>
<ref bean="purgeCartConfig"/>
</list>
</property>
</bean>
<bean id="purgeCartTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="purgeCartJobDetail" />
<property name="startDelay" value="30000" />
<property name="repeatInterval" value="86400000" />
</bean>
Valid parameters in the purgeCartConfig
map are:
- SECONDS_OLD - number of seconds since the last update date of the cart
- STATUS - comma-delimited status from
OrderStatus
. For instance, if you wanted to clean up allIN_PROCESS
(carts) andNAMED
(wishlists) orders:
<entry key="STATUS" value="IN_PROCESS,NAMED" />
- NAME - the name of
NAMED
Orders to delete. This is useful if your implementation uses specific names of wishlist or saved carts and they are not normally user-specified - IS_PREVIEW - "true" or "false" for the value of the
IS_PREVIEW
column on Order. This is mainly used in enterprise.
Anonymous Customers can also be cleaned up. While Broadleaf does not persist a new Customer on every single visit, new Customers are persisted when a user adds something to their cart. This is an example of a quarts job that cleans up all non-registered Customers that have not been updated in the last 30 days:
<bean id="purgeCustomerConfig" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
<entry key="SECONDS_OLD" value="2592000"/>
<entry key="IS_REGISTERED" value="false"/>
</map>
</property>
</bean>
<bean id="purgeCustomerJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="blResourcePurgeService" />
<property name="targetMethod" value="purgeCustomers" />
<property name="arguments">
<list>
<ref bean="purgeCustomerConfig"/>
</list>
</property>
</bean>
<bean id="purgeCustomerTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="purgeCustomerJobDetail" />
<property name="startDelay" value="30000" />
<property name="repeatInterval" value="86400000" />
</bean>
Valid parameters in the purgeCustomerConfig
map are:
- SECONDS_OLD - number of seconds since the last update date of the Customer
- IS_REGISTERED - "true" or "false" for the value of the registered field on Customer
- IS_DEACTIVATED - true" or "false" for the value of the deactivated field on Customer
- IS_PREVIEW - "true" or "false" for the value of the
IS_PREVIEW
column on Customer. This is used in enterprise.
Database-managed System Properties
Rather than managing system properties only via Runtime Environment Configuration, you can now manage properties in the database via the BLC_SYSTEM_PROPERTY
table. If the property is not found in the database, then the fallback is to look for the property in property files configured according to Runtime Environment Configuration.
If you would like to take advantage of this functionality then you can remove an @Value
annotation on a bean property and override the getter to invoke BLCSystemProperty
like so:
protected boolean getSomeBeanProperty() {
BLCSystemProperty.resolveBooleanSystemProperty("some.bean.property");
}
This is how we refactored the TranslationRequestProcessor
to determine if translations should be enabled:
@Component("blTranslationRequestProcessor")
public class TranslationRequestProcessor extends AbstractBroadleafWebRequestProcessor {
// ...
protected boolean getTranslationEnabled() {
return BLCSystemProperty.resolveBooleanSystemProperty("i18n.translation.enabled");
}
// ...
}
Thymeleaf 2.1
We have continued and enhanced our usage of Thymeleaf by updating to the latest GA version. To see what comes with Thymeleaf 2.1, see their What's new in Thymeleaf 2.1 page.
Friendly Permissions
We refactored admin permissions to make them more intuitive for adding to users and roles. The idea here is that if you want to give permissions to a user or role for a certain section of the admin, all you need to do is add either of the friendly permissions for that section ("View [section]" or "Maintain [section]"). We added a boolean value on Permission
called isFriendly
which indicates that this is a permission that contains child permissions maintained through BLC_ADMIN_PERMISSION_XREF
.
Resolved GitHub Issues Reference
An at-a-glance view of the issues that were closed in this release:
Critical Bugs(3)
- Offers that have been deleted (e.g. ARCHIVED='Y') still show up in the admin. They should be suppressed as they are considered deleted.
- PageServiceImpl creates PageDTO CMS URL's incorrectly (inconsistent with StaticAssetPathService and StructuredContentService)
- StructuredContentService is rewriting the path incorrectly
Major Bugs(22)
- Use of select DISTINCT sql can cause an exception in Oracle when a CLOB field is in play
- Calling OrderService.deleteOrder causes an exception
- Order.getEmailAddress() is null when merging an anonymous cart into a newly registered Customer's cart
- Update validations are ignored in admin 3.1
- Change password no longer works with Salt
- JSessionID is causing problems with forgot password flow
- Editing an entity with MatchesFieldValidator in use will throw an NPE
- Don't used required validation on offer target criteria, as a blank value is a valid case in 3.1
- Upload new asset button not displaying when choosing an asset from product or category
- Update setOrderSubtotalToPriceWithoutAdjustments to call calculateSubtot...
- Admin polymorphic addition of site map generator configuration shows all fields
- Cannot edit site map generator configuration in admin anymore
- Cannot delete Store from within the admin
- IndexOutOfBounds in ContentProcessor when fieldFilters are specified but none of the content applies.
- StructuredContentService buildFieldValues is not consistent with StaticAssetPathService build asset path
- JAXRS JSON serialization of a collection of 1 object does not render an array
- Fix incorrect comparison causing verify fulfillment groups to fail unexp...
- FontAwesome icons are not loading in the admin
- Editing a AdminPresentationCollection annotated collection item in the admin with an addType of PERSIST doesn't refresh the list grid properly
- The dirty flag on properties is not being tracked in the admin
- ExtensionManager classes cannot be used by open-admin
- ProductDaoImpl possibly using obsolete Join on 'allProducts'
Minor Bugs(13)
- IS_FRIENDLY in load_admin_permissions.sql PostgreSQL can not cast Integer
- Fix Checkout Form Validators
- Utilize Hibernate for customer login
- Occasionally, product images do not render on the first visit
- Exception when viewing entity that doesn't have a menu entry
- Don't shift order for fields marked as alternate order
- Upgrade to HSQLDB to version 2.3.1
- Sku hasSalePrice checking retail instead of sale
- Listgrids cannot have toolbar buttons in a readonly grid
- Structured Content changes do not always persist when going through the service
- Properly render list grid global/row-level separator
- Remove unused columns from admin section
- The BLC.js addUrlParam method is missing a '?'
Features(26)
- Provide ability for URLHandler to use regex
- Provide framework for cross app authentication support
- SystemProperty enhancements
- Add support for managing robots.txt file via the admin CMS as a custom page
- Enterprise workflow support
- Upgrade Thymeleaf to latest 2.1.RELEASE Version
- Refactor Payment Domain and Unify Paradigms
- Add the ability for parent/child relationships in OrderItem
- Refactor to allow BLC to run without the CMS module
- Create a pluggable file service
- Allow image uploads to be hosted on S3 or Rackspace Cloudfiles
- Add support for SiteMaps to framework
- The FormBuilderServiceExtensionHandler should support all entity form creations
- Provide the ability to link to an admin page from a content item
- Allow configurable sorts in the content processor
- Add a processor to obtain data driven enumerations
- Expose several protected methods in StructuredContentService
- Allow multiple modules to add functionality to the ContentProcessor
- Allow multiple modules to extend the process of going from StructuredContent -> StructuredContentDTO
- Add ability to load a page directly to a specified listgrid
- Add the ability to retrieve BroadleafRequestContext variables in Thymeleaf
- Add ability to get the servlet context via JavaScript
- Provide a mechanism to return JSON or XML error structures from REST services
- Create cart/customer cleanup job
- allow product options to be updated after item in cart
- add validate product options activity to checkout workflow
Enhancements(53)
- Prevent double-click actions on forms
- Ensure SystemProperty lookups are optimized
- Refactor Permissions to make adding them to roles and users simpler
- Add ability to override shipping and tax prices
- Provide Thymeleaf Processor for Checking System Configuration Variables
- Ensure that offer codes and offer criteria are dealt with appropriately when an offer is archived
- In ChangePasswordValidator, use isPasswordMatch
- Change password no longer works with Salt
- Misc. enhancements to support for Content Testing module
- Remove archived column from the admin for payments
- Provide the ability to hide/show the ID column on list grids
- Fix the SolrIndexService to ignore a null document.
- Give the ability to change usernames for customers
- Do not allow an order to go through the checkout workflow multiple times
- Allow performCheckout to be thread safe in the context of a particular order
- Change page to not require a locale
- Add PERMISSION_OTHER_DEFAULT by default
- Refactor Offer Services to allow for module extensions
- In BroadleafSearchController searchRedirectService is private and not accessible from the subclass
- Order gets repriced multiple times when adding order item with child items
- Need invocation handler for unit testing byte-weaved classes
- Update JUnit version to 4.11
- Model Product --> ProductOption as a first class entity
- Add hook for modifying ListGridRecords in the FormBuilderService
- Need the ability to make polymorphic additions in admin edit screens
- There should be a way to override how customers are resolved from a request
- Ensure Thymeleaf configuration loads exclusively via XML
- add find stores by state in StoreService
- EntityForm needs to allow specification of read-only state
- Make PaymentInfo implement Status (see OfferImpl) to support soft deletes
- Allow list grid actions to have an action override URL
- Remove Sandbox behavior from Page and StructuredContent
- Remove password change fields from admin user edit
- Do not maintain duplicated functionality for data-driven enums for CMS fields
- Update StoreService to match changes in store dao and entity.
- Allow store entity to easily be extended and added as an admin section
- Create a helper utility for executing MVEL rules
- 3.1.0 Miscellaneous internal improvements
- Deprecate/Remove the terms AccountCredit and AccountPayment from Checkout/Payment workflows
- add a stub checkout rollback handler for payments
- Add event handler support for CriteriaTranslator
- Create a property that points to the currently configured front-end site
- SupportedFieldType of HTML and HTML_BASIC should be handled by the BasicFieldPersistenceProvider, rather than the fall-back DefaultFieldPersistenceProvider
- Add ability to select multiple rows in a list grid
- Add a pre and post event model for CRUD operations in the admin
- Create a response object that better details the result of CRUD operations in the PersistenceManager in the admin
- Support parsing basic field types when retrieving structured content
- Allow dynamic fields to be marked as required
- Refactor FormBuilderServiceExtensionManager and MainEntityActionsExtensionManager to use the generic ExtensionManager classes
- Add encoding property to EmailInfo for VelocityMessageCreator
- Refactor Email Services to remove implementations args from method signatures
- Deprecated Method Cleanup
- Add "translation" support for BLC locales
Total Resolved Issues: 119