Elastic Path's QA team is using ApTest as its test case repository. The tool is online, so we can access it on or off site. We have divided testing of our application into modules based on the functional areas; ie, order modifications, catalog management, import/export, payment gateways, reporting, promotions, etc.

Each each release has its own test suite. We use the release as the suite name, ie. Release 6.1. The Release 6.1 suite includes all the test cases from previous releases plus test cases for new functionality added in 6.1. For the next release, 6.1.1, we will copy the Release 6.1 suite to a new suite called Release 6.1.1 and add new functionality test cases to it as well. This method allows us to go back to each release and know what has been added, what is new and what we have covered so far. When there are changes to existing functionality, we deal with the changes by making sure we keep test cases up to date.

We have both manual and automated test cases in ApTest. Manual test cases have a full description, pre- and post-conditions, and expected result(s). For automated test cases, we have only placeholders in ApTest. We use Fit for business logic. (Fit will be discussed in more detail in another post). The Fit tests run automatically at build time and we parse the results back into ApTest. This helps us for reporting purposes.

Test cases are run as part of a session. The session can be one big session containing all the test cases, or small sessions based on the functional areas with test cases specific to that functional area.

Writing test cases

After logging in to ApTest, click the suites button (the second button next to help, which looks like a color palette) to list all the suites that you have access to. Then select the suite you want by clicking the link. Select 'Specify Test Cases for this Test Suite'. On the left hand side, you can see the module names. Select one. In the frame on the right side, you can see either the test cases in a grid table or some other folders (these are the subfolders under the selected module). In the right side frame, at the top next to the module name/test case name, there are some buttons:

  • 'Make a new folder': This creates subfolder under the specific module you are working in.
  • 'Make a new Test Case': This will open the template for test cases and you can fill up the necessary information and create the test cases.
  • 'Rename/Move Folder': This will allow renaming of the folder or the subfolder currently in; also it allows moving the folder to some other place within the same suite.
  • 'Delete Folder': This will allow deletion of the folder or subfolder currently working in.
  • 'Copy Folder': This will copy the current folder and test cases within the same suite.
  • 'Manage Folder': This would allow adding description to the folder or locking the folder.
  • 'Find and Replace': This gives the search capability within the current folder and its subfolders.
  • 'Upload File': This will allow upload of a file such as .csv or .txt files
  • 'Import Tests': This will allow mass import of test cases.
  • 'Arrange test cases and folders': This would allow the folder and test case ordering.

Running test cases

On the page directed to by selecting the release, select 'Execute Test Cases in this Test Suite'. In order for test cases to run we need to have a set of test cases in a session.

If you already have a session, select your session from the table, check the check mark next to the session, and click the yellow/green foot shape icon.

 

If you don't have a session, you need to create the sets and sessions.

  1. Click the 'Administer Sets and Sessions' button at the top of the page. On the right side frame on top next to the release name there are few buttons.
  2. Click 'Add a New Folder' to create a folder.
  3. Click 'Add a New Test Set'. Give a meaningful name to the test set and select test cases, or any of the functional area, version, who created it or priority. Create the test set.
  4. In the test set table, find your test set just created.
  5. Next to the test set, there is a tiny file with a green + next to it labelled 'Create Test Session'. Click it. Name your session and select your parameters. The test environment set up is pretty much what your test server settings are. Then create test session.
  6. Now you can find this session in the session table, check the check mark next to it, and click the yellow/green foot shape icon.

 

Now you can go through test cases one by one and flag them as failed, passed or ignored.

0 Comments 0 References Permalink

In order to maintain persistent shopping carts and wish lists, EP stores session data as customers shop.  Without maintenance, the database tables will grow over time and may lead to performance problems when customers re-visit the site as the system searches through large tables.  This post explains some methods to purge these tables.

 

Of course, we strongly recommend testing these commands in a test environment before touching your production site.  Also, note that some of these commands may take a long time to execute if the tables are very large.

 

A session is created whenever a customer shops. If the customer adds items to a cart or wishlist, the session creates a cart with the associated item(s).  If the customer is identified by cookie or sign-in, the session will reference the customer ID; if not, the session customer ID will be null because the customer is not known.  The database works as follows:

 

Items are linked to carts by a SHOPPING_CART_UID (items contain a reference to the shopping cart primary key)

Carts are linked to sessions by a GUID (reference to session primary key)

Sessions are linked to customers by a CUSTOMER_ID (reference to customer primary key) if the customer is identified; otherwise CUSTOMER_ID is null

 

Because every visit creates a session, the TCUSTOMERSESSION table is the largest and may have sessions with or without known customer ID and with or without a cart.

 

There are a couple ways to purge these tables.  The easiest is simply to delete all entries in the TCUSTOMERSESSION table that have no associated shopping cart or items (i.e. customer browsed but did not add anything to a cart or wishlist).  In SQL, this means deleting all TCUSTOMERSESSION records with a GUID that is not found in the TSHOPPINGCART table.  You should add a time parameter to delete only sessions older than x days - that way you don't delete active or relatively recent carts.  This should get rid of the majority of entries. Look at the data or pull a count before deleting to see how it will affect your store.  The basic SQL looks like this:

 

delete from DB.TCUSTOMERSESSION where GUID not in (select GUID from DB.TSHOPPINGCART);

 

Another more aggressive way is to delete all TCUSTOMERSESSION records where the CUSTOMER_UID is NULL.  This deletes all carts created for unidentified shoppers (whether or not they are empty), but risks orphan carts that have to be cleaned up.  The SQL is:

 

delete from DB.TCUSTOMERSESSION where CUSTOMER_UID is null;

 

This clears out all the sessions for unidentified shoppers, but will likely leave orphan carts in TSHOPPINGCART.  The way to delete these is to first delete all items from all orphaned carts BEFORE deleting the carts, and then to delete all carts whose GUID is not in the TCUSTOMERSESSION table.  The basic SQL would look like below; as you can see, the end of the first command is the same as the second command because first we?re searching for ?sessionless? carts to delete their items and then we?re deleting the sessionless carts themselves.

 

delete from DB.TCARTITEM where SHOPPING_CART_UID in (select UIDPK from DB.TSHOPPINGCART where GUID not in (select GUID from DB.TCUSTOMERSESSION));

 

and then

 

delete from DB.TSHOPPINGCART where GUID not in (select GUID from DB.TCUSTOMERSESSION);

 

Note that these two methods delete different entities: one deletes sessions that never had carts, the other deletes sessions with unidentified shoppers (that may or may not have carts) and then deletes the orphaned carts.

 

Finally, you can delete the (relatively few) carts that had no items in them:

 

DELETE FROM DB.TSHOPPINGCART WHERE UIDPK NOT IN (SELECT SHOPPING_CART_UID FROM DB.TCARTITEM);

 

These can be done on a running store, but remember to add a time parameter so you don't delete current carts that customers are planning to buy.  And remember to test this in your test environment first!

1 Comments 0 References Permalink

The intent of this post is to clear up some foggy notions and misconceptions about the Elastic Path 6.1 development environment, as well as provide a few insider tips and tricks. Developers of CM Client modules will probably find the following more helpful than web or core application developers, but the principles can be used by everyone.


If you're doing any development of the CM Client and you make a change to EP Core, and you want that change to be available in the CM Client, your typical build time shouldn't be more than a minute or so, hopefully much less. Let's clarify:

When you're running the CM Client from within Eclipse, the CM Client will not use the CORE jar; it will use the CORE project's class files directly.
This means that you do NOT have to run "ant all" on the command line (I never run it - it takes forever).

Let's look at a typical day of developing some new feature in the CM Client where you might be changing some code in the EP Core project. If (and only if) you have changed any persistent classes in the core (i.e. domain objects), you have to make sure that JPA has "enhanced" these classes before you can use them, right? So you have two choices (maybe more, but these are the two that I see):

  1. run "ant enhance" in the com.elasticpath.core project and refresh the project in eclipse. This ensures that JPA has a chance to modify the class files that eclipse's compiler created and then eclipse doesn't think its knowledge of the class files is out-of-date. This takes a few seconds.
  2. run "ant build" in one of the web projects (e.g. com.elasticpath.cm), which will rebuild the core project, enhance its class files, and refresh the core jar file that the webapp will use if you're running it outside of eclipse (which most of us don't do anyway - we run it with WTP inside eclipse, so once again the project files are used rather than the core jar file). This takes about 15 seconds on my box (unless maven connections are having problems, but that's a separate issue).


So in a typical developer environment for EP 6.1, using WTP to run the webapps, the CORE jar is never actually used. So it doesn't have to be built, and it certainly doesn't have to be copied anywhere for the CM Client to use it.

Now for some caveats:

  1. If you have previously built the CM Client on the command-line (ant all, ant build-product, etc) you will likely see that it has created a jar file for each plugin in each of the plugin directories. You must delete these or you will find that changes to the code for that plugin are not reflected in the running copy (if it finds a jar, it will use that jar instead of your project code).
  2. The com.elasticpath.ql project seems to be referenced as a jar file from the com.elasticpath.cmclient.libs project. You must build this project once on the commandline so that its jar is created; otherwise you'll find that running the CM Client won't work because the Spring initializer is expecting some code that it cannot find. This often catches developers who have just imported all their eclipse projects and they try to run the CM Client. If you're developing on this ql project you likely already know this; if you're not, then you only have to do this once and you can forget about it.
  3. When setting up a new workspace, you *do* have to do an "ant eclipse-setup" once in the com.elasticpath.cmclient directory to make sure that all the CM Client plugins have eclipse project files generated for them, which you can import into eclipse. The list of projects for which project files will be generated lives in the build.xml file in that directory. If you're adding a new plugin, you will need to add it to that list so that its project file is generated properly (with maven information, etc).
  4. Each Web project requires a META-INF/context.xml file for you to be able to run it in tomcat with WTP. This file is generated by the eclipse-setup script if you've got tomcat specified in your env.config file when you run the script, but I believe it's wiped out when you run "ant clean"... so don't run that, or if you do then make sure you run ant eclipse-setup again.



0 Comments 0 References Permalink

Search Server Failover

Posted by Alan Schroder Jan 21, 2009

Every Elastic Path administrator knows: if your search server goes down, your storefront is down and so is Commerce Manager. You can make your Elastic Path deployment more resilient by setting up search server failover.

 

In a nutshell, you set up two machines to run the search server web application. One is the main search server (master). The other is a backup (slave). Both machines are running behind a load balancer. The master search server uses rsync to synchronize multiple index files to the slave machine and then commits these new indexes into the slave's indexes. This essentially creates a duplicate of the master on the slave and, if the master server goes down, the slave server will be able to handle all requests.

 

The failover configuration consists of three components:

  • The master server
  • The slave server
  • The load balancer.

The load balancer is a PC running Apache web server with the mod_proxy module. The master server contains the search server web application, the index builders, and the indexes. The slave server also contains the search server web application, but it does not build its own indexes. Instead, the master uses rsync to replicate the search index files to the slave. Then, the data in the updated index files is committed into the slave search server's indexes. During normal operation, this machine receives search requests and forwards them to the master.

SSFailover_Figure1.png

If the master becomes unavailable, due to a failure or planned downtime, the load balancer redirects search requests to the slave.

SSFailover_Figure2.png

To make it all work, there are some scripts that need to get run by cron jobs on the master and slave. Note these scripts use rsync and Unix hard-links, so they only work on Linux/Unix environments.

 

You also need to set the searchHost setting in Elastic Path to point to the proxy server.

 

You can download the scripts and the setup documentation from the downloads page.

0 Comments 0 References Permalink

Many classes were refactored in Elastic Path 6.1 to improve testability of existing code and to accommodate new features (most notably the ability for a single Storefront WAR file to host multiple Stores). Here are the changes with the highest impact for developers (in no particular order).

1. Refactoring of ElasticPathImpl.java and Creation of the Settings Framework

ElasticPathImpl covers several distinct areas of responsibility: BeanFactory, Configuration, Filtered Navigation, asset lookup... In 6.1, new interfaces were created to move those areas of functionality out of ElasticPathImpl with the intention of rendering the object obsolete in future versions.

  • Most configuration settings are now accessed via the SettingsService, which will be covered in a separate article. Commerce-config.xml files are no longer used to populate a map of settings in ElasticPathImpl, with the exception of the one in the CM web application, which is only used to keep track of the EP version and build number
  • Asset locations are now retrieved from the AssetRepository interface (see heading elsewhere in this article)
  • Search Configuration is now retrieved entirely from the Settings framework rather than from the ElasticPath object
  • Filtered Navigation information is still retrieved from ElasticPathImpl, but only because it implements the new FilteredNavigationConfiguration interface. The actual retrieval implementation now lives in a separate class and references the new Settings framework
  • Bean instances can still be retrieved from ElasticPath because ElasticPathImpl implements the BeanFactory interface, but from this point onward the ElasticPath object is not required to be injected into classes that only need a BeanFactory. Instead, you should inject an implementation of BeanFactory

If any customizations were performed on some Elastic Path 6.0 code base that must be transferred to an Elastic Path 6.1 code base, most careful attention should be paid to any changes in the ElasticPath singleton, especially if any new settings were introduced that are designed to be read in from a commerce-config.xml configuration file. Since most settings were moved to the Settings framework, the code to parse the configuration file has mostly been removed.

New customizations should pay special attention to the Settings framework and use it where appropriate. Also, the BeanFactory should be injected into new classes where required instead of the ElasticPath object, as its use as a bean factory is being phased out.

New persistent classes should have a DAO that is separate from any new services, to allow for more flexible persistence implementations if functionality changes.

2. Testing Framework Enhancements

In testing, the big news is deprecation of ElasticPathTestCase.java and the introduction of JUnit4 and JMock2 testing frameworks.

Prior to 6.1, many test classes extended ElasticPathTestCase.java, which is a JUnit 3.8 extended test class that mocks out much of the application's domain using mock objects created with the JMock 1.x framework. This class is being phased out, and use of it is no longer recommended because it:

  • is large and unwieldy
  • encourages poor code factoring and integration tests using mock objects
  • is complex; modification may affect many test cases in an unforeseen manner

 

Instead, unit test classes should focus on unit-testing rather than integration-testing methods. Use of the JUnit4 and JMock2 framework features should help in that regard. There are many examples of their use in the new code; but for a start you may want to look at GiftCertificateThemeImplTest (for a relatively simple test class) and StoreResourceManagerImplTest (which takes advantage of some advanced features in the new JMock framework).

3. New Store UI Themes and Asset Retrieval

Store-specific Velocity template resolution has been introduced. Most static and storefront theme content (storefront velocity templates, email velocity templates, javascript files, css files, Power Reviews, etc) was moved outside the separate application WAR files into the pre-existing Assets folder on the file system.

 

In 6.0 only some assets (store images and digital goods) lived on the file system under the assets folder, while others (email templates, storefront UI files, and PowerReviews files) lived inside the WAR. All of these files were moved to appropriate locations under the file system's assets folder and the paths to such folders were made available through an AssetRepository object rather than through methods on the ElasticPath object. This allows the assets to be modified at runtime.

 

The Storefront application's Themes feature (see Themes documentation) required the introduction of a StoreResourceManager to handle Velocity's lookups and caching for Storefront velocity templates. It does not use the AssetRepository, but instead uses very similar code combined with hardcoding the velocity template directory within the assets folders (see StoreVelocityConfigHelper.java). A separate Velocity Engine is created for each and every Storefront operating within a WAR.

The Storefront's asset requests that are not for Velocity templates (e.g. css, javascript, images, Power Reviews) go through the AssetResourceController, which uses the AssetRepository indirectly through an AssetRetrievalStrategy. In order for controllers to know which store they are working with, a ThreadLocal reference to Store has been introduced, set by the StoreSelectionFilter. Any storefront controller requiring parameters specific to the store that is accessing the controller can inject the StoreConfig object, or they can retrieve it from the RequestHelper, which also has it injected. The current store is no longer retrieved from ElasticPath.java.

4. New DAO classes

New DAO classes were introduced in some areas to separate service logic from persistence operations. In addition to some new features using separate Service and DAO classes, existing Services which have had DAO functionality factored out include:


  • ProductService / ProductDao
  • ProductTypeService / ProductTypeDao

 

DAO classes should generally not be accessed directly from outside of the Service layer. Such separation of business logic and persistence logic allows for far more flexibility and decoupling in the application. Future development should endeavor to follow this pattern (See the GiftCertificateThemeService / GiftCertificateThemeStoreAssignmentDao for an example of how such decoupling can be of benefit).

5. Index UID / GUID fields

We are phasing out UID fields in the indexes, in favor of GUID fields, for greater decoupling. Secondary object UID fields have, for the most part, been replaced with GUID fields in object indexes so that searches can be performed based on GUIDs. For instance, the CategoryIndex contains the CategoryUid so that the UID can be retrieved from the index when a search match is found, but the index is built using the GUIDs from associated objects (e.g. you can search the CategoryIndex to return categories that are associated with a particular CatalogCode, but not with a particular CatalogUid). The corresponding SearchCriteria objects have been modified to reflect the index schema changes.

Index fields that have been modified as a result of this change are as follows:


  • CategoryIndex:

 

  • parentCategoryUids replaced with parentCategoryCodes
  • catalogUid replaced with catalogCode

 

  • PromotionIndex

 

  • promotionRuleSetUid continues to live in the index, but the promotionRuleSetName is now also in the index. This is for legacy reasons (the PromotionSearchCriteria object still contains both fields as well), and the UID field is expected to be removed in a future version of Elastic Path.
  • catalogUid continues to live in the index, but catalogCode is now also in the index. This is for legacy reasons (the PromotionSearchCriteria object still contains both fields as well), and the UID field is expected to be removed in a future version of Elastic Path.

 

  • ProductIndex

 

  • CategoryUid replace with CategoryCode
  • parentCategoryUids replaced with parentCategoryCodes
  • catalogUid replaced with catalogCode
  • Addition of a new storeCode field

 

In addition, several fields were added to the OrderReturn index schema.

6. Improved Index Build Status Tracking

The status of indexes, and the method of causing them to rebuild, has changed drastically:


  • The index build status (including the last time the index was built) is stored in the new TINDEXBUILDSTATUS database table, and can be accessed using the IndexBuildStatusService.
  • On the Search Server, the AbstractIndexServiceImpl class manipulates the status of index builds directly through the IndexBuildStatusDao.
  • The Commerce Manager Client has a new View that enables index rebuilds to be triggered manually.

 

In addition, if the server is brought down (either manually or catastrophically) while in the process of building an index, it will now remember its status upon restart and will start a new rebuild rather than assuming that the index is complete.

7. New Store Editor GUI

The Store Editor has been enhanced to better handle store themes. In addition, it has abstracted most of the business logic from where it may previously have been embedded in the UI code.

0 Comments 0 References Permalink

Using Maven (http://maven.apache.org/) for dependency management frees developers from having to manually download and manage third-party dependencies. This greatly simplifies the process of upgrading third-party libraries and gives developers more time to work on actual development. Maven provides a number of features to simplify dependency management. The core concept is the idea of project object model files (poms). Poms are a standardized way to describe a project: group, artifact, name, version, dependencies, layout, etc.

Inheritance of Dependency Versions

Versions of third-party libraries can be specified in a high-level/parent pom. This allows subprojects that need a certain dependency to leave the version empty and use the one specified in the parent. Upgrading all projects to use a newer third-party library is as simple as changing one version number in the parent pom.

Transitive Dependencies

Since each dependency specifies its own dependencies, only direct dependencies of a project need to be specified. Any other runtime dependencies of those dependencies will be included automatically. i.e. If project A specifies B as a dependency and B requires C and D to run, then A will automatically get B, C, and D.

Dependency Fetching

Maven also includes automatic downloading and caching of dependencies. As new dependencies are required during the build process, Maven will check for a local copy. If there is no local copy, Maven will automatically download it.

In order to move from Antlion to Maven, we need to make a number of changes in our build scripts and configuration files:

  • The old jars.xml file has been removed and replaced by a dependency management section in our top-level pom, elasticpath.pom
  • All of the per-project dependency listings in the artifact.xml files have been removed and placed in pom.xml files within each project

 

For the most part, developers do not need to know much about Maven; it operates transparently behind Ant. However, when you need to change or add dependencies, some knowledge of the setup is required.

 

At Elastic Path, we have an internal Maven repository, managed by an instance of Archiva (http://archiva.apache.org). It not only provides a place to keep custom/missing dependencies, but also acts as a proxy to various public Maven repositories. If a newly added dependency is available in the public repositories, it will be automatically fetched and cached by Archiva.

Adding New jars

When a dependency cannot be found in any public repositories, or when a dependency has been patched or customized, it will need to be manually deployed to Archiva. At present, this requires Maven to actually be installed on the computer doing the deployment. Then the following steps need to be performed.

 

1. Create a pom for the jar if none exists. If the jar was patched or customized, append something to the version to indicate this (ex. 2.5.5-clientA-projectX-1.0).

2. Choose the repository to deploy to:

 

  • Internal - artifacts available from public Maven repositories.
  • Extras - artifacts not found in a Maven repository.
  • Custom - open-source libraries that have been patched or customized.
  • Restricted - libraries that are not redistributable, but are required internally during development and testing.
  • Other - if you are working on a project that is customizing the EP platform you should probably have a repository (or repositories) created specifically for your project which will make it easier to tell which libraries you need to redistribute.

 

3. Edit ~/.m2/repository/settings.xml file to specify your Archiva username and password.

<servers>
<server>
 <id>deployment.webdav</id>
 <username>{archiva-deployment-user}</username>
 <password>{archiva-deployment-pwd}</password>
</server>
</servers>

 

4. Create a new folder from where you will deploy the jar and create a pom there with the following content:

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>webdav-deploy</artifactId>
<packaging>pom</packaging>
<version>1</version>
<name>Webdav Deployment POM</name>

<build>
 <extensions>
 <extension>
 <groupId>org.apache.maven.wagon</groupId>
 <artifactId>wagon-webdav</artifactId>
 <version>1.0-beta-2</version>
 </extension>
 </extensions>
</build>
</project>

 

5. Navigate on the command line to the folder created in the previous step and run the following command.

 

mvn deploy:deploy-file -Dfile=filename.jar -DpomFile=filename.pom

-DrepositoryId=deployment.webdav

-Durl=dav:http://maven.elasticpath.net/archiva/repository/{repository}

Setting up a Project

To set up a new project, you need to create a pom file.

 

1. Copy an existing pom to use as a starting point (com.elasticpath.cm/pom.xml for a new web project or com.elasticpath.ql/pom.xml for a jar).

2. Modify the artifactId, packaging, name, and description to reflect the new project.

3. Leave the parent section alone as it will allow you to inherit settings from the main EP pom.

4. Remove all the dependencies that are not required, and add any new ones that are needed.

5. Review the build section and modify the directories as required.

 

Since we are still using Ant to do the actual building, the build.xml and artifact.xml files will also have to be created. Copy and modify existing ones from the project you copied the pom from.

Using Proper pom Versions

If any modifications are made to an existing project, make sure to open the pom.xml and modify the version string. If there is no version setting, the project was inheriting the parent pom's version and one will have to be added. During active development the version string for a new or modified project should be something like 6.1-clientA-projectX-SNAPSHOT. For each release the version should be changed to something like 6.1-clientA-projectX-1.0 and then ...-1.1, ...-1.2, etc. This tells anyone looking at it exactly which EP release it was based on and for which client/project it was for.



0 Comments 0 References 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

If you've always dreamed of integrating Facebook/Flickr/WordPress/Mediawiki with Elastic Path, read on. Elastic Path's web services let you access some EP functionality remotely from the client platform of your choice.

First, make sure you've deployed the com.elasticpath.connect web app properly. See the section on deploying Elastic Path web apps in the Elastic Path 6.1 Deployment Guide.

Next, if you don't already know, find out what web services are available in your version of Elastic Path. Take a look at WEB-INF/web.xml in the directory where you deployed the webservices webapp. The <servlet-mapping> elements show you the URL patterns to use to access each of supported web services. For example, in my setup, I have the following:

 

<!-- Servlet mappings -->
   <servlet-mapping>
      <servlet-name>shoppingcart_web_service</servlet-name>
      <url-pattern>/shoppingcartwebservice</url-pattern>
   </servlet-mapping>

   <servlet-mapping>
      <servlet-name>order_web_service</servlet-name>
      <url-pattern>/orderwebservice</url-pattern>
   </servlet-mapping>

   <servlet-mapping>
      <servlet-name>association_web_service</servlet-name>
      <url-pattern>/associationwebservice</url-pattern>
   </servlet-mapping>

    <servlet-mapping>
       <servlet-name>import_web_service</servlet-name>
       <url-pattern>/importwebservice</url-pattern>
    </servlet-mapping>

   <servlet-mapping>
      <servlet-name>inventory_web_service</servlet-name>
      <url-pattern>/inventorywebservice</url-pattern>
   </servlet-mapping>

   <servlet-mapping>
      <servlet-name>catalog_web_service</servlet-name>
      <url-pattern>/catalogwebservice</url-pattern>
   </servlet-mapping>

   <servlet-mapping>
      <servlet-name>customer_web_service</servlet-name>
      <url-pattern>/customerwebservice</url-pattern>
   </servlet-mapping>

So, the available web services are:

  • shoppingcartwebservice (displays shopping cart items)
  • orderwebservice (view, hold, release orders)
  • associationwebservice (get product associations)
  • importwebservice (run import jobs, like from the Commerce Manager)
  • inventorywebservice (view and adjust inventory)
  • catalogwebservice (access the catalog, add products)
  • customerwebservice (view and add customers)

For our purposes, you'll want to disable the secure channel redirect in webservices\WEB-INF\conf\spring\security\acegi.xml:

 

<bean id="channelProcessingFilter" class="org.acegisecurity.securechannel.ChannelProcessingFilter">
      <property name="channelDecisionManager"><ref bean="channelDecisionManager"/></property>
      <property name="filterInvocationDefinitionSource">
            <!-- Comment this out:
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                                \A/.*\Z=REQUIRES_SECURE_CHANNEL
</value>
     -->
            <!-- Add this: -->
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
</value>
</property>
    </bean>

Note that if you want to use SSL, there is an issue with PHP not being able to retrieve the WSDL over SSL. As a workaround, download the WSDL (and all referenced files) to your PHP host and repoint all references to the local versions.

Now is a good time to test if web services are deployed and configured properly on your system. A quick way to do this is to try a web service URL in a browser. For example:

http://localhost:11080/webservices/shoppingcartwebservice?wsdl

Note that I tested this using the Elastic Path trial installer, so you can try this out without having to do a full-blown EP deployment. You should get back an XML document that looks similar to the following.

wsdl.jpg

 

Next, install soapUI. soapUI is a great tool for inspecting WSDLs and testing web services. After it's installed, start it and create a project. (In the File menu, choose New soapUI Project.)

In the dialog, enter a project and enter the URL of the web service.

 

soapui_01.jpg


Click OK. When it's done, you'll see that the project has been added to the navigator pane on the left. Under the project, you can see the methods available in the web service. If you expand one of the methods, you'll see a Request 1 node beneath it.

soapui_02.jpg

 

Select Request 1. In the Request Properties pane (under the navigator), enter the user name and password of the Commerce Manager administrator user (or use the login of a user with web services permissions, if one exists.)

 

soapui_03.jpg


Double-click Request 1. You'll see the XML that would be sent if you called the method from a web service client.

 

soapui_04.jpg

 

You can even call that method by replacing the question marks with actual values and clicking the the green arrow button. The results are displayed in the pane on the right. (Don't forget to set up your environment properly before trying out web service calls. For example, if you want to try the shopping cart service as shown here, you'll need to log a user in to the store front and add items to the cart.)

 

I find this a great way to experiment with a service, without having to worry about the details of setting up your particular client platform. Once you've got a feel for how it works, the next step is to set up PHP and write some code.

  1. Install Apache and PHP 5.1 or later. For convenience, you can install Xampplite, which includes a complete LAMP/WAMP suite (Apache, PHP, Perl, MySQL, ...).
  2. In the php.ini file, do the following:
    1. Set soap.wsdl_cache_enabled to 0. For development purposes, you don't want to cache the WSDLs.
    2. Make sure the PHP SOAP extension is enabled (i.e., you have the following line with no semi-colon (;) at the beginning):
      extension=php_soap.dll
  3. Restart Apache.
  4. Write PHP code. Here's an example that uses the shopping cart web service to display items in a user's shopping cart:
    <html>
    <head><title>Elastic Path Web Services Test</title></head>
    <body>
    <h1>Elastic Path Web Services Test</h1>
    <?php
    // construct a SOAP client
    $wsdl = 'http://ep-ww-pmonk:7001/webservices/shoppingcartwebservice?wsdl';

    // if SSL is used, must download wsdl and xsd and refer to that
    //$wsdl = 'shoppingcartwebservice.wsdl';

    // set client options, including CM admin or web service user name and password
    $options = array(
    'trace' => 1,
    'login' => 'admin',
    'password' => 'password'
    );

    try{
    // create the service proxy
    $cartService = new SoapClient($wsdl, $options);

    // fill an object with the parameters
    $getCartRequestObj->UserId = 'paul.monk@example.org';
    $getCartRequestObj->StoreCode = 'SNAPITUP';

    // wrap that object (container property name must be the xxxRequest type in the WSDL (e.g., GetCartRequest))
    $getCartObj->GetCartRequest = $getCartRequestObj;

    // call the service method
    $result = $cartService->getCart($getCartObj);

    // display the results
    print '<p>Your shopping cart contains these items:</p><table><tr><th>Quantity</th><th colspan="2">Item</th></tr>';
    $cart = $result->return->shoppingCart;
    foreach($cart->CartItems->CartItem as $cartItem){
    $tr ='<tr>';
    $qty = $cartItem->Quantity;
    $tr .= '<td>' . $qty . '</td>';
    $productSku = $cartItem->ProductSku;
    $tr .= '<td>' . $productSku->Code . '</td>';
    $tr .= '<td><img src="http://ep-ww-pmonk.elasticpath.net:7001/storefront/renderImage.image?imageName=' .
    $productSku->Image->FileName . '&width=200&height=200&padding=0"/></td></tr>';
    print $tr;
    }
    print '</table>';

    }
    catch(SoapFault $fault){
    print '<pre>';
    var_dump($fault);
    var_dump(htmlspecialchars($cartService->__getLastRequest()));
    var_dump(htmlspecialchars($cartService->__getLastResponse()));
    print '</pre>';
    }
    ?>
    </body>
    </html>

For more info on PHP's SOAP extension, see the PHP SOAP documentation.

Once you've experimented a bit, you may want to start looking at exposing more of Elastic Path's functionality as web services. You'll want to look at the section on web services architecture in the Elastic Path 6.1 Developer Guide.

0 Comments 0 References Permalink