Technical Blog

5 Posts tagged with the configuration tag

One of the quirks that I used to have while developing using binary based development is the fact that we have multiple maven projects, and changes to one of the projects (ie. core) will need to be rebuilt in other projects that depend on it (ie. storefront).

 

This was typical what I had to do:

 

cd project-root
cd core-project
mvn clean install

<take a nap for a few minutes>

<check to make sure the project built successfully>

cd ../storefront-project
mvn clean install

 

The other option is to build all the projects in the workspace.

 

cd project-root
mvn clean install

<take a longer nap for 10 minutes>

 

That is actually ineffective and a waste of time. One could argue you can write a script that will invoke those commands for you. However, you'd have to check for cases whent the build fails. Luckily, I found that there is a maven plugin that helps with automating that for us.

 

This is where the Maven Reactor plugin comes to the rescue.

 

The solve the previous problem where you changed your core project and only want to build the storefront, all you have to do is type this in the project-root directory:

 

mvn reactor:make -Dmake.folders=storefront-project

 

The Maven Reactor plugin will build core-project and then the storefront-project for you. If there is a problem with the core project (ie. compilation failures), it will stop the build and tell you.

4 Comments Permalink

Hello all,

 

In a recent project we began using the @Autowired spring annotation in our objects and services to help simplify and minimize the amount of configuration we were writing in our various xml files.

 

Introduced in Spring 2.5 annotation-based configurations are now a viable alternative to pure XML configuration.  While it is debatable if one approach is “better” than the other, in practice it seems that mixing both methods allows you to spend less time wiring everything up and just getting on with it.

 

There are a number of annotations available including support for JSR-250 and JSR-330 but for this article I will be focusing purely on the @Autowired annotation.  For more information please refer to the Spring documentation or any number of articles on the web.

 

What’s the point?

 

How many times have you had to explicitly wire your spring beans and services hunting for the proper bean names?  What about creating setter methods for your private objects?  What if there were an easier way to do it?

 

Spring 2.5 (and beyond) has introduced a new xml context schema that deals with ApplicationContext configuration related to plumbing – that is, not usually beans that are important to an end-user but rather beans that do a lot of the grunt work in Spring, such as BeanFactoryPostProcessors.  To enable the tags in the context namespace, simply add the context namespace to your schema definition:

 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<!-- <bean/> definitions here -->

</beans>

 

 

Now let’s look at a class as an example to see how @Autowired can help you in your daily development.

 

package emptest;
public interface EmployeeService {
         String hire(String name);
         String fire(String name);
}
 
 
package emptest.impl;
@Service
public class EmployeeServiceImpl implements EmployeeService {
 
         private EmployeeDao employeeDao;
 
         public String hire(String name) {
                 String message = employeeDao.getMessage("Hire");
                 return name + ", " + message;
         }
 
         public String fire(String name) {
                 String message = employeeDao.getMessage("Fire");
                 return name + ", " + message;
         }
 
         public void setEmployeeDao(EmployeeDao employeeDao) {
                 this.employeeDao = employeeDao;
         }
}
 

 

In this simple example we have a service implementing an interface with a private DAO object.  In a typical spring configuration for this service typically you would define your bean as:

 

 

<bean id="employeeService" class="emptest.impl.EmployeeServiceImpl">
         <property name="employeeDao">
                 <ref bean=”employeeDao”/>
         </property>
</bean>

 

 

But Spring can automatically detect classes and register bean definitions with the ApplicationContext!  Let’s see how this works in practice.

 

Step 1.  Add <context:component-scan base-package=”emptest.impl”/> to your configuration file.  This tells spring to scan everything in the emptest.impl package for Spring stereotypes and annotations.

 

 

<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
     xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

     <context:component-scan base-package="emptest.impl"/>


</beans>

 

 

Step 2.  Add @Autowired annotation to any private objects that you would like Spring to wire up for you.

 

package emptest.impl;
@Service
public class EmployeeServiceImpl implements EmployeeService {
         @Autowired
         private EmployeeDao employeeDao;
 
         public String hire(String name) {
                 String message = employeeDao.getMessage("Hire");
                 return name + ", " + message;
         }
 
         public String fire(String name) {
                 String message = employeeDao.getMessage("Fire");
                 return name + ", " + message;
         }        
}
 
 

 

That’s it!  Notice that there is no need to explicitly define a setter method, nor do you need to explicitly define your bean within the Spring configuration.

 

Of course this is a very basic scenario, but for the most part will get you started using annotation based configuration.  There are lots of tutorials, guides and documentation available online for more advanced usages.

 

Cheers!

1 Comments Permalink

This post walks through adding filtering to the System Configuration page in the CM Client helping you track down a setting as quickly as possible.

 

We added the Settings Framework in Elastic Path Commerce 6.1 and it's proved incredibly useful in centralizing configuration and easing customization versus the previous XML based approach.  The number of settings out-of-the-box continues to grow plus any additional ones that customers are free to add.  So this tip will show you how to reign in that growing number of settings.

 

Here's a screenshot of what we'll be producing, if you've spent any time in the System Configuration (like our trusty QA guys) this will be a real time saver.

 

settings-filter.png

 

Changing the layout

I had to refresh my SWT widget layout knowledge a little and found this great page: http://www.eclipse.org/articles/article.php?file=Article-Understanding-Layouts/index.html.  With that excellent refresher I decided I would need a three column GridLayout: a column each for the Edit button, filter label and the filter text widget.  The table would then span all three columns.

 

settings-filter-layout.png

First, simply change the number of columns on the SettingDefinitionComposite:

 

private void setupLayout() {
     final int columns = 3;
     this.setLayout(new GridLayout(columns, false));
}

 

Then add in a horizontal span to the table's LayoutData - this makes it span the three columns we just created.

final int horizontalSpan = 3;
table.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, horizontalSpan, 1));

Note: the final variables are to keep Checkstyle quiet about magic numbers.

 

Adding the new widgets

The code below adds the label and the filter Text widget.  Take a close look at the style we are using to create the Text widget with: SWT.SEARCH | SWT.CANCEL.  The SWT.SEARCH style gives us the rounded edges (at least on my Mac) which makes it look like a regular search/filter widget.  The SWT.CANCEL style adds the small cross to the widget.  When clicked it removes the currently entered text.

Label label = formToolkit.createLabel(this, AdminConfigurationMessages.filterLabel + ":"); //$NON-NLS-1$
GridData gridData = new GridData(SWT.END, SWT.CENTER, false, false);
label.setLayoutData(gridData);
Text settingNameFilter = formToolkit.createText(this, "", SWT.SEARCH | SWT.CANCEL); //$NON-NLS-1$
gridData = new GridData(SWT.FILL, SWT.CENTER, false, false);
final int verticalIndent = 10;
gridData.verticalIndent = verticalIndent;
settingNameFilter.setLayoutData(gridData);

 

We want this new addition to be localizable so we need to add AdminConfigurationMessages.filterLabel

public static String filterLabel;

 

And then we provide the English version of that in AdminConfigurationPluginResources.properties

 

filterLabel=Filter

 

Filtering

Now we'll take a look at how we will actually filter down the table's contents.  The code's pretty simple:

/**
 * Filter setting definitions against a specified string.
 */
private class SettingPathFilter extends ViewerFilter {
     private final String filterText;
     public SettingPathFilter(final String filterText) {
          this.filterText = filterText;
     }
     @Override
     public boolean select(final Viewer viewer, final Object parent, final Object element) {
          SettingDefinition definition = (SettingDefinition) element;
          return StringUtils.containsIgnoreCase(definition.getPath(), filterText);
     }
}

We've simply extended the JFace ViewerFilter class and implemented the select method with a case-insensitive check against the setting definition's path.  In the next step we'll create an instance of this class and pass it to the TableViewer that holds the setting definitions.

 

The following page helped me a bit with the ViewerFilter: http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/DemonstratesListViewer.htm

 

Hooking it together

The bits are all in place, let's tie them together and get the filtering going when a user types in the text box.  We simply add a ModifyListener to the filter Text widget and when we receive a ModifyEvent we grab the user-entered string, create a new SettingPathFilter and set that on the tableViewer.  That triggers the tableViewer to filter its contents.  Note: I chose to use setFilters, rather than addFilter/removeFilter, to keep the code simple: I don't have to keep track of the filter to remove it afterwards I simply call setFilters again.

 

settingNameFilter.addModifyListener(new ModifyListener() {
     public void modifyText(final ModifyEvent event) {
          final Text source = (Text) event.getSource();
          String filterText = source.getText();
          if (StringUtils.isBlank(filterText)) {
               tableViewer.setFilters(new ViewerFilter [0]);
          } else {
               tableViewer.setFilters(new ViewerFilter [] {new SettingPathFilter(filterText)});
               }
     }
});

 

 

Conclusion

So there you have it, all done, with a few small changes we can find settings without having to visually scan the table.  Where else might this filtering function be useful?  Anyone done any similar customizations they would like to share?

 

The code

The code changes and the attached patch are against the upcoming 6.2 release, but I'm pretty sure they will apply to any 6.1+ version.  Leave a comment if you have any problems applying this and I'll do my best to help you out.

References

http://www.eclipse.org/swt/snippets/ - if you've not taken a look at the SWT snippets then you're missing out.  There's a ton of useful examples of using SWT.

http://wiki.eclipse.org/index.php/JFaceSnippets - just like the SWT snippets, this page contains great snippets about using the JFace ui toolkit.

2 Comments Permalink

Elastic Path 6.1 provides a new way to manage your application configuration. In the past, settings were stored in a variety of places throughout the system; some were in XML files, others were in properties files, and still others were stored in different tables in the database. Now, the most commonly used settings are stored in the database and can be configured using the Commerce Manager.

Custom settings can be migrated to use this framework with little code change and would be able to take advantage of Elastic Path 6.1 multi-store setting management features.

Setting Definitions

Setting definitions are stored in the database, in the TSETTINGDEFINITION table. A setting definition contains:

 

  • a path
  • a default value
  • a value type
  • the maximum number of overrides

 

The path is a unique identifier for the setting. For example COMMERCE/STORE/giftcertificatesEnabled path refers to the setting that sets whether gift certificates are enabled for a given store.

The default value is the fallback to use when a specific value hasn't been assigned to the setting.

 

The value type indicates the type of value stored in the setting (a string, a number, a URL, etc.).

 

The maximum number of overrides specifies the number of values that can be assigned to a setting. Some settings can have multiple values assigned to them. Others can only have one. For example, a store-specific setting would need to have different values for different stores, so the number of overrides would be very large or unlimited (-1). For a system-wide setting, there is generally only one override.

Setting Values

The TSETTINGVALUE table contains the values that have been assigned to settings. Each value has a context. For system settings, the context is empty. For store-specific values, the context contains a store code.

Setting Metadata

Setting metadata is stored in the TSETTINGMETADATA table. It can be used to store additional configuration information relating to the setting. A setting can have any number of metadata associated with it.

Setting metadata consists of a set of key/value pairs. In Elastic Path 6.1, there are two metadata key/value pairs that can be assigned to settings:

 

  • RefreshStrategy, which defines the setting's refresh strategy

 

  • availableToMarketing, which indicates whether the setting is displayed in the store Marketing tab.

 

Setting Refresh Strategies

The setting refresh strategies metadata provides fine-grained control over when setting changes are applied to the system. In the past, most setting changes required restarting the server. Now, when the setting change is applied depends on how you've configured its refresh strategy. Out of the box, Elastic Path 6.1 provides four refresh strategies:

 

  • application: settings that use the application refresh strategy are only applied after the application is restarted

 

  • session: settings that use the session refresh strategy do not change during the lifetime of the user's session. If an administrator changes the setting value, users will not see the change until their session cookie is removed or expires and a new session is created

 

  • interval: settings that use the interval refresh strategy are cached for a specified period of time. Users do not see changes until the cache expires

 

  • immediate: settings that use the immediate refresh strategy are updated immediately. As soon as the administrator changes a setting that uses this strategy, the change is applied everywhere

Creating a Setting Definition

New setting definitions can be added by executing SQL insert statements. For example, the following creates a definition identified by the path CUSTOM/WIDGETS/widgetType:

INSERT INTO TSETTINGDEFINITION(UIDPK, PATH, DEFAULT_VALUE, VALUE_TYPE, MAX_OVERRIDE_VALUES)
VALUES(10001, "CUSTOM/WIDGETS/widgetType", "flat", "String", 0, 1);

 

For your custom settings, you should use a naming convention, to avoid conflicts with other settings. Do not use the COMMERCE path prefix, which is reserved for Elastic Path settings.

Adding a Value for the Setting

Setting values can be added by using the Commerce Manager client application. For more information, see the Commerce Manager User Manual.

You can also use SQL insert statements. Remember that you don't need to create a setting value if there is a default value that comes from the setting definition.

Assuming you do want to override the setting definition for a specific context (store code for stores), you can create the value with the following SQL:

INSERT INTO TSETTINGVALUE(UIDPK, SETTING_DEFINITION_UID, CONTEXT, CONTEXT_VALUE)
 VALUES(1011, 10001, "SLRWORLD", "circle")

 

Note the value of SETTING_DEFINITION_UID should match the UIDPK for the related row in TSETTINGDEFINITION.

Note that multiple setting values can be defined on a setting definition if the setting definition's max_override_values field is set to -1.

 

Settings Framework Services

Elastic Path 6.1 provides a low level SettingsService class to manage and retrieve of setting definitions and values. To get a setting value for a system level setting with no context:

SettingsService settingsService = getElasticPath()
   getBean(ContextIdNames.SETTINGS_SERVICE);
final int numOfMinutes = Integer.valueOf(settingsService.getSettingValue(
   "COMMERCE/APPSPECIFIC/RCP/idleTimeForLock").getValue());

 

To get a setting value for a particular context:

settingsService.getSettingValue(path, store.getCode()).getValue();

 

If there is no setting value in TSETTINGVALUE for the specified context, the system will fall back to the default value in TSETTINGDEFINITION. For example, the default value of the COMMERCE/STORE/giftcertificatesEnabled setting is false, but a setting value for the context SNAPITUP is true, so the Snap It Up store has gift certificates enabled.

 

A SettingsReader service interface is provided for read only operations. Additionally, the CachedSettingsReader service wrapper provides caching for settings retrieval, and is the preferred method in the storefront to avoid frequent database calls.

 

In storefront controllers, the StoreConfig object (available through the RequestHelper) can be used to obtain setting values. If a store specific value is available, it will automatically be retrieved. Otherwise, the default value from the setting definition is returned.  For example:

String pagination = getRequestHelper().getStoreConfig()
 getSetting("COMMERCE/STORE/CATALOG/catalogViewPagination").getValue();
int paginationNumber = NumberUtils.toInt(pagination, DEFAULT_PAGINATION);

 

Elastic Path 6.1's settings framework should replace usage of configuration files for custom configuration settings, especially where multiple stores are being deployed. Previous code retrieving settings from the ElasticPathImpl object should be migrated to the settings framework and its suite of APIs.

0 Comments 0 References Permalink

     

Elastic Path Commerce 6.1 introduces a number of changes from version 6.0.x. Primary among these are a major change to the store asset directory structure; movement of store configuration information from the file system to the database; and a number of minor changes to the existing database tables. As a result, 6.0.4 deployments with existing data can be upgraded to the 6.1 codebase with relocation of store assets; migration of configuration files into the database; and database upgrade scripts.

 

Note that it's assumed that the codebase has already been upgraded to 6.1; it's up to you to decide how code merge is done. It's also assumed that the existing deployment was already at the latest service release (6.0.4) before upgrading to 6.1.


Store Assets Relocation

Along with the XML configuration files, store-specific visual presentation elements used in the Storefront and emails have been moved from the WAR files into a central assets directory.  These include all Velocity templates, message properties files, images, javascript, css and Power Reviews.

 

  • The simplest way to move storefront assets out of the WAR file is to copy the directories com.elasticpath.sf/template-resources and com.elasticpath.sf/WEB-INF/templates to the new assets directory under a theme folder of your choosing. The assets directory will have the structure:

 

assets/themes/<theme_name>/<store_code>/templates

assets/themes/<theme_name>/<store_code>/template-resources

 

  • Email templates previously located in com.elasticpath.cm/WEB-INF/templates also need to be moved to the assets folder. Email templates and property files that are not connected to any particular store will need to be moved to: assets/cmassets/templates/velocity

 

  • Storefront related emails will be located under their respective theme folders: assets/themes/<theme_name>/<store_code>/templates/velocity

Configuration File Migration

Much of the configuration data previously in XML files within Elastic Path WAR directories has been moved into the database to be managed through the Settings framework in the CM. This includes commerce-config.xml, search-config.xml, urlrewrite.xml, intelligent-browsing.xml. Please consult the settings framework documentation before migrating configuration settings.

 

  • With the exception of web.sf.context.url, all settings previously in commerce-config.xml have been moved to the Settings framework and are no longer required to be in the XML file. Values in these settings (e.g. VFS paths/login) should be updated in the Settings framework through the CM Settings configuration view as new Setting values or inserted into tables TSETTINGVALUE where appropriate. Additional custom settings in commerce-config.xml file should be moved to the Settings framework as new Setting definitions in TSETTINGDEFINITION. A table of where settings in the commerce-config.xml reside in the settings framework is provided in Appendix A.

 

  • Content in intelligent-browsing.xml has been moved to the Settings framework and the file is no longer needed. Its contents should be inserted as a new Setting Value for the setting COMMERCE/STORE/FILTEREDNAVIGATION/filteredNavigationConfiguration

 

The content can also be copied into the CM Store Editor's Filtered Navigation section.

 

  • Content in urlrewrite.xml has been moved to the Settings framework and the file is no longer needed. Its contents should be inserted as a new Setting Value for the setting COMMERCE/SYSTEM/urlRewriteConfig

 

  • Content in search-config.xml has been moved to the Settings framework and the file is no longer needed. If any customization has been made, the Setting values under the paths COMMERCE/SEARCH/<setting> should be updated appropriately.

Database Upgrade

Upgrade SQL scripts are provided along with each release of Elastic Path to capture changes in the database schema between the new release and the latest service release.

Each supported database (MySQL, SQL Server, Oracle) will have its own upgrade script.

 

  • Upgrade scripts are provided in the 6.1 distribution for each database, and should be run by the tools provided by the database vendor.
  • Upgrade scripts will apply schema changes and insert necessary base data on an existing 6.0.x database, but does not change existing data.

 

After running the upgrade script, the steps can be done through the CM or directly through the database to get your deployment up and running:

 

  • Reassign supported currency and supported locales to existing stores in the CM, or insert entries in the TSTORESUPPORTEDCURRENCY and TSTORESUPPORTEDLOCALE respectively.
  • Change the display theme of existing stores appropriately by editing the COMMERCE/STORE/theme setting in either the System Configuration section of the CM or the Store Editor.
  • Set the correct value for the search server in the settings framework, under the path COMMERCE/SERVER/SEARCH/searchHost
  • Search indexes need to be rebuilt. This is an automatic step if old indexes are deleted.
  • Set the correct values for the asset VFS in the settings framework under COMMERCE/APPSPECIFIC/RCP/ASSETS/<setting>
  • Gift certificate themes need to be recreated through the CM, and assigned to stores in the CM Store Editor.
  • Be aware that stores can now only be accessed through the URL defined in the CM Store Editor (TSTORE table in the databse), and care should be taken when testing.

Caveats

  • The upgrade process cannot cover all possible database and code customizations to the 6.0.x codebase, and upgrade scripts should be reviewed before running on any schemas that you have customized.
  • Before moving existing storefront assets, be aware that there are changes in these files (Velocity templates, property files) that might not be picked up through a normal code merge due to the change in location.
  • New configuration settings introduced in 6.1 take on their default values after an upgrade, and should be reviewed for correctness.

 

Upgrading to 6.1 from 6.0.4 requires little database change. Configuration files and asset migration make up the bulk of the upgrading effort, and existing customizations to configuration and assets should be reviewed to take advantage of the new settings framework and asset repository.

0 Comments 0 References Permalink