killbill-memoizeit

Changes

account/pom.xml 104(+75 -29)

api/pom.xml 5(+5 -0)

catalog/src/main/java/com/ning/billing/catalog/PlanChangeCase.java 130(+0 -130)

catalog/src/test/java/com/ning/billing/catalog/TestCancelCase.java 123(+0 -123)

catalog/src/test/java/com/ning/billing/catalog/TestPlanChangeCase.java 265(+0 -265)

entitlement/src/main/java/com/ning/billing/entitlement/alignment/EntitlementAlignment.java 148(+0 -148)

pom.xml 4(+2 -2)

Details

account/pom.xml 104(+75 -29)

diff --git a/account/pom.xml b/account/pom.xml
index fda1f24..a899a89 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -1,33 +1,79 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright 2010-2011 Ning, Inc.
-  ~
-  ~ Ning licenses this file to you under the Apache License, version 2.0
-  ~ (the "License"); you may not use this file except in compliance with the
-  ~ License.  You may obtain a copy of the License at:
-  ~
-  ~    http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-  ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-  ~ License for the specific language governing permissions and limitations
-  ~ under the License.
-  -->
+<!-- ~ Copyright 2010-2011 Ning, Inc. ~ ~ Ning licenses this file to you 
+	under the Apache License, version 2.0 ~ (the "License"); you may not use 
+	this file except in compliance with the ~ License. You may obtain a copy 
+	of the License at: ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless 
+	required by applicable law or agreed to in writing, software ~ distributed 
+	under the License is distributed on an "AS IS" BASIS, WITHOUT ~ WARRANTIES 
+	OR CONDITIONS OF ANY KIND, either express or implied. See the ~ License for 
+	the specific language governing permissions and limitations ~ under the License. -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>com.ning.billing</groupId>
-        <artifactId>killbill</artifactId>
-        <version>0.0.3-SNAPSHOT</version>
-        <relativePath>../pom.xml</relativePath>
-    </parent>
-    <artifactId>killbill-account</artifactId>
-    <name>killbill-account</name>
-    <packaging>jar</packaging>
-    <dependencies>
-    </dependencies>
-    <build>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>com.ning.billing</groupId>
+		<artifactId>killbill</artifactId>
+		<version>0.0.3-SNAPSHOT</version>
+		<relativePath>../pom.xml</relativePath>
+	</parent>
+	<artifactId>killbill-account</artifactId>
+	<name>killbill-account</name>
+	<packaging>jar</packaging>
+	<dependencies>
+		<dependency>
+			<groupId>org.jdbi</groupId>
+			<artifactId>jdbi</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.google.inject</groupId>
+			<artifactId>guice</artifactId>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.ning.billing</groupId>
+			<artifactId>killbill-util</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>joda-time</groupId>
+			<artifactId>joda-time</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.skife.config</groupId>
+			<artifactId>config-magic</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-log4j12</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.testng</groupId>
+			<artifactId>testng</artifactId>
+			<scope>test</scope>
+		</dependency>
+
+	</dependencies>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<configuration>
+					<groups>setup,fast</groups>
+				</configuration>
+			</plugin>
+		</plugins>
     </build>
 </project>
diff --git a/account/src/main/java/com/ning/billing/account/api/Account.java b/account/src/main/java/com/ning/billing/account/api/Account.java
new file mode 100644
index 0000000..283f141
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/api/Account.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.account.api;
+
+import java.util.UUID;
+
+import com.ning.billing.catalog.api.Currency;
+
+public class Account implements IAccount {
+
+    private final UUID id;
+    private final String key;
+
+    public Account(String key) {
+        this(UUID.randomUUID(), key);
+    }
+
+
+    public Account(UUID id, String key) {
+        super();
+        this.id = id;
+        this.key = key;
+    }
+
+    @Override
+    public UUID getId() {
+        return id;
+    }
+
+    @Override
+    public String getKey() {
+        return key;
+    }
+
+    @Override
+    public String getName() {
+        return null;
+    }
+
+    @Override
+    public String getEmail() {
+        return null;
+    }
+
+    @Override
+    public String getPhone() {
+        return null;
+    }
+
+
+    @Override
+    public int getBillCycleDay() {
+        return 0;
+    }
+
+    @Override
+    public Currency getCurrency() {
+        return null;
+    }
+
+    @Override
+    public void setPrivate(String name, String value) {
+    }
+
+    @Override
+    public String getPrivate(String name) {
+        return null;
+    }
+}
diff --git a/account/src/main/java/com/ning/billing/account/dao/IAccountDao.java b/account/src/main/java/com/ning/billing/account/dao/IAccountDao.java
new file mode 100644
index 0000000..ed9693e
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/dao/IAccountDao.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.account.dao;
+
+import java.util.List;
+import java.util.UUID;
+
+import com.ning.billing.account.api.IAccount;
+
+public interface IAccountDao {
+
+    public void createAccount(IAccount account);
+
+    public IAccount getAccountByKey(String key);
+
+    public IAccount getAccountFromId(UUID uid);
+
+    public List<IAccount> getAccounts();
+
+}
diff --git a/account/src/main/java/com/ning/billing/account/dao/IAccountDaoSql.java b/account/src/main/java/com/ning/billing/account/dao/IAccountDaoSql.java
new file mode 100644
index 0000000..c7068c1
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/dao/IAccountDaoSql.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.account.dao;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.UUID;
+
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.customizers.Mapper;
+import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.IAccount;
+
+
+public interface IAccountDaoSql extends Transactional<IAccountDaoSql>, CloseMe {
+
+    @SqlUpdate("insert into accounts (id, key_name) values (:id, :key_name)")
+    public void insertAccount(@Bind(binder = IAccountSqlBinder.class) IAccount account);
+
+    @SqlQuery("select id, key_name from accounts where key_name = :key_name")
+    @Mapper(IAccountSqlMapper.class)
+    public IAccount getAccountByKey(@Bind("key_name") String key);
+
+    @SqlQuery("select id, key_name from accounts where id = :id")
+    @Mapper(IAccountSqlMapper.class)
+    public IAccount getAccountFromId(@Bind("id") String id);
+
+    @SqlQuery("select id, key_name from accounts")
+    @Mapper(IAccountSqlMapper.class)
+    public List<IAccount> getAccounts();
+
+
+    public static class IAccountSqlBinder implements Binder<Bind, IAccount> {
+
+        @Override
+        public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, IAccount account) {
+            stmt.bind("id", account.getId().toString());
+            stmt.bind("key_name", account.getKey());
+        }
+    }
+
+    public static class IAccountSqlMapper implements ResultSetMapper<IAccount> {
+
+        @Override
+        public IAccount map(int index, ResultSet r, StatementContext ctx)
+                throws SQLException {
+            UUID id = UUID.fromString(r.getString("id"));
+            String key = r.getString("key_name");
+            return new Account(id, key);
+        }
+    }
+}
diff --git a/account/src/main/java/com/ning/billing/account/glue/AccountModule.java b/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
new file mode 100644
index 0000000..cf917ce
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.account.glue;
+
+import org.skife.config.ConfigurationObjectFactory;
+import org.skife.jdbi.v2.DBI;
+
+import com.google.inject.AbstractModule;
+import com.ning.billing.account.dao.AccountDao;
+import com.ning.billing.account.dao.IAccountDao;
+import com.ning.billing.dbi.DBIProvider;
+import com.ning.billing.dbi.DbiConfig;
+
+public class AccountModule extends AbstractModule {
+
+    protected void installConfig() {
+        final IAccountConfig config = new ConfigurationObjectFactory(System.getProperties()).build(IAccountConfig.class);
+        bind(IAccountConfig.class).toInstance(config);
+    }
+    protected void installDBI() {
+        bind(DBI.class).toProvider(DBIProvider.class).asEagerSingleton();
+        final DbiConfig config = new ConfigurationObjectFactory(System.getProperties()).build(DbiConfig.class);
+        bind(DbiConfig.class).toInstance(config);
+    }
+
+    protected void installAccountDao() {
+        bind(IAccountDao.class).to(AccountDao.class).asEagerSingleton();
+    }
+
+    @Override
+    protected void configure() {
+        installConfig();
+        installDBI();
+        installAccountDao();
+    }
+
+}
diff --git a/account/src/main/java/com/ning/billing/account/glue/IAccountConfig.java b/account/src/main/java/com/ning/billing/account/glue/IAccountConfig.java
new file mode 100644
index 0000000..c95c351
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/glue/IAccountConfig.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.account.glue;
+
+public interface IAccountConfig {
+
+}
diff --git a/account/src/main/resources/ddl.sql b/account/src/main/resources/ddl.sql
new file mode 100644
index 0000000..996af37
--- /dev/null
+++ b/account/src/main/resources/ddl.sql
@@ -0,0 +1,10 @@
+CREATE DATABASE IF NOT EXISTS killbill;
+
+USE killbill;
+
+DROP TABLE IF EXISTS accounts;
+CREATE TABLE accounts (
+    id char(36) NOT NULL,
+    key_name varchar(128) NOT NULL,
+    PRIMARY KEY(id)
+) ENGINE=innodb;
diff --git a/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java
new file mode 100644
index 0000000..2903bce
--- /dev/null
+++ b/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.account.dao;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Stage;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.IAccount;
+import com.ning.billing.account.glue.AccountModule;
+
+public class TestSimpleAccountDao {
+
+
+    private IAccountDao dao;
+
+    public static void loadSystemPropertiesFromClasspath( final String resource) {
+        final URL url = TestSimpleAccountDao.class.getResource(resource);
+        assertNotNull(url);
+
+        try {
+            System.getProperties().load( url.openStream() );
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    private  Injector getInjector() {
+        return Guice.createInjector(Stage.DEVELOPMENT, new AccountModule());
+    }
+
+
+    @BeforeClass(groups={"setup"})
+    public void setup() {
+        //loadSystemPropertiesFromClasspath("/account.properties");
+        final Injector g = getInjector();
+
+        dao = g.getInstance(IAccountDao.class);
+    }
+
+    @Test(enabled=true, groups={"sql"})
+    public void testBasic() {
+
+        IAccount a = new Account("foo");
+        dao.createAccount(a);
+
+        IAccount r = dao.getAccountByKey("foo");
+        assertNotNull(r);
+        assertEquals(r.getId(), a.getId());
+        assertEquals(r.getKey(), a.getKey());
+
+        r = dao.getAccountFromId(a.getId());
+        assertNotNull(r);
+        assertEquals(r.getId(), a.getId());
+        assertEquals(r.getKey(), a.getKey());
+
+        List<IAccount> all = dao.getAccounts();
+        assertNotNull(all);
+        assertEquals(all.size(), 1);
+    }
+
+
+}
diff --git a/account/src/test/resources/log4j.xml b/account/src/test/resources/log4j.xml
new file mode 100644
index 0000000..11c2c9c
--- /dev/null
+++ b/account/src/test/resources/log4j.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2010-2011 Ning, Inc.
+  ~
+  ~ Ning licenses this file to you under the Apache License, version 2.0
+  ~ (the "License"); you may not use this file except in compliance with the
+  ~ License.  You may obtain a copy of the License at:
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+  ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+  ~ License for the specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
+        <param name="Target" value="System.out"/>
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%p	%d{ISO8601}	%X{trace}	%t	%c	%m%n"/>
+        </layout>
+    </appender>
+
+
+    <logger name="com.ning.billing.account">
+        <level value="debug"/>
+    </logger>
+
+    <root>
+        <priority value="info"/>
+        <appender-ref ref="stdout"/>
+    </root>
+</log4j:configuration>
diff --git a/analytics/pom.xml b/analytics/pom.xml
index 4bda36b..de64a5c 100644
--- a/analytics/pom.xml
+++ b/analytics/pom.xml
@@ -48,7 +48,7 @@
         </dependency>
         <dependency>
             <groupId>com.ning.jetty</groupId>
-            <artifactId>ning-service-skeleton-core</artifactId>
+            <artifactId>ning-service-skeleton-utils</artifactId>
         </dependency>
         <dependency>
             <groupId>commons-io</groupId>
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
index 0940d13..3d04806 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
@@ -82,8 +82,8 @@ public class BusinessSubscription
             final IProduct product = currentPlan.getProduct();
             productName = product.getName();
             productCategory = product.getCategory();
-            if (product.getType() != null) {
-                productType = product.getType().getName();
+            if (product.getCatalogName() != null) {
+                productType = product.getCatalogName();
             }
             else {
                 productType = null;
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionEvent.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionEvent.java
index 956339e..f0d503d 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionEvent.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionEvent.java
@@ -128,7 +128,7 @@ public class BusinessSubscriptionEvent
         final IPlan currentPlan = subscription.getCurrentPlan();
         if (currentPlan != null && currentPlan.getProduct() != null) {
             final IProduct product = currentPlan.getProduct();
-            if (product.getType() != null && product.getCategory() != null) {
+            if (product.getCatalogName() != null && product.getCategory() != null) {
                 return product.getCategory();
             }
         }
diff --git a/analytics/src/main/java/com/ning/billing/analytics/setup/AnalyticsModule.java b/analytics/src/main/java/com/ning/billing/analytics/setup/AnalyticsModule.java
index b50ad8c..efeb970 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/setup/AnalyticsModule.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/setup/AnalyticsModule.java
@@ -19,7 +19,8 @@ package com.ning.billing.analytics.setup;
 import com.google.inject.AbstractModule;
 import com.ning.billing.analytics.dao.EventDao;
 import com.ning.billing.analytics.dao.EventDaoProvider;
-import com.ning.jetty.core.providers.DBIProvider;
+import com.ning.jetty.utils.providers.DBIProvider;
+
 import org.skife.jdbi.v2.DBI;
 
 public class AnalyticsModule extends AbstractModule
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockPlan.java b/analytics/src/test/java/com/ning/billing/analytics/MockPlan.java
index fefa76c..a2baa37 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockPlan.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockPlan.java
@@ -21,7 +21,7 @@ import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.IPlan;
 import com.ning.billing.catalog.api.IPlanPhase;
 import com.ning.billing.catalog.api.IProduct;
-import com.ning.billing.catalog.api.PlanAlignment;
+import com.ning.billing.catalog.api.PlanAlignmentChange;
 
 import java.util.Iterator;
 
@@ -73,18 +73,6 @@ public class MockPlan implements IPlan
     }
 
     @Override
-    public BillingAlignment getBillingAlignment()
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public PlanAlignment getPlanAlignment()
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public int getPlansAllowedInBundle()
     {
         throw new UnsupportedOperationException();
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockProduct.java b/analytics/src/test/java/com/ning/billing/analytics/MockProduct.java
index 62d7b5a..958de9a 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockProduct.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockProduct.java
@@ -17,7 +17,6 @@
 package com.ning.billing.analytics;
 
 import com.ning.billing.catalog.api.IProduct;
-import com.ning.billing.catalog.api.IProductType;
 import com.ning.billing.catalog.api.ProductCategory;
 
 public class MockProduct implements IProduct
@@ -34,16 +33,9 @@ public class MockProduct implements IProduct
     }
 
     @Override
-    public IProductType getType()
+    public String getCatalogName()
     {
-        return new IProductType()
-        {
-            @Override
-            public String getName()
-            {
-                return type;
-            }
-        };
+        return type;
     }
 
     @Override
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscription.java b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscription.java
index 79a81f1..7ac53fd 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscription.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscription.java
@@ -85,7 +85,7 @@ public class TestBusinessSubscription
         Assert.assertEquals(subscription.getPrice(), phase.getRecurringPrice().getPrice(null));
         Assert.assertEquals(subscription.getProductCategory(), product.getCategory());
         Assert.assertEquals(subscription.getProductName(), product.getName());
-        Assert.assertEquals(subscription.getProductType(), product.getType().getName());
+        Assert.assertEquals(subscription.getProductType(), product.getCatalogName());
         Assert.assertEquals(subscription.getStartDate(), isubscription.getStartDate());
     }
 

api/pom.xml 5(+5 -0)

diff --git a/api/pom.xml b/api/pom.xml
index d38ffe1..ac32a68 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -49,6 +49,11 @@
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
         </dependency>
+        <dependency>
+			<groupId>org.skife.config</groupId>
+			<artifactId>config-magic</artifactId>
+		</dependency>
+        
     </dependencies>
     <build>
     </build>
diff --git a/api/src/main/java/com/ning/billing/catalog/api/ICatalog.java b/api/src/main/java/com/ning/billing/catalog/api/ICatalog.java
index 0e533b1..f583753 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/ICatalog.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/ICatalog.java
@@ -21,16 +21,12 @@ import java.util.List;
 
 public interface ICatalog {
 
-	public abstract IProductType[] getProductTypes();
-
 	public abstract IProduct[] getProducts();
 
 	public abstract IPriceList[] getPriceLists();
 
 	public abstract IPriceList getPriceListFromName(String priceListName);
 
-	public abstract List<IProduct> getProductsForType(IProductType productType);
-
 	public abstract IPlan getPlan(String productName, BillingPeriod term, String priceList);
 
 	public abstract Currency[] getSupportedCurrencies();
@@ -52,7 +48,16 @@ public interface ICatalog {
 
     public abstract ActionPolicy getPlanCancelPolicy(PlanPhaseSpecifier planPhase);
 
-    public abstract PlanAlignment getPlanAlignment(PlanPhaseSpecifier from, PlanSpecifier to);
+    public abstract void configureEffectiveDate(Date date);
+
+    public abstract String getCalalogName();
+
+    public abstract PlanAlignmentCreate getPlanCreateAlignment(PlanSpecifier specifier);
+
+    public abstract BillingAlignment getBillingAlignment(PlanPhaseSpecifier planPhase);
+
+    public abstract PlanAlignmentChange getPlanChangeAlignment(PlanPhaseSpecifier from,
+			PlanSpecifier to);
 
 	
 }
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/catalog/api/IPlan.java b/api/src/main/java/com/ning/billing/catalog/api/IPlan.java
index e9efa97..cb13510 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/IPlan.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/IPlan.java
@@ -32,8 +32,6 @@ public interface IPlan {
 
 	public abstract BillingPeriod getBillingPeriod();
 
-	public abstract BillingAlignment getBillingAlignment();
-
 	public abstract int getPlansAllowedInBundle();
 
 }
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/catalog/api/IProduct.java b/api/src/main/java/com/ning/billing/catalog/api/IProduct.java
index af82794..7ea2a21 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/IProduct.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/IProduct.java
@@ -19,8 +19,6 @@ package com.ning.billing.catalog.api;
 
 public interface IProduct {
 
-	public abstract IProductType getType();
-
 	public abstract String getName();
 
 	public abstract IProduct[] getAvailable();
@@ -29,4 +27,6 @@ public interface IProduct {
 
 	public abstract ProductCategory getCategory();
 
+	public abstract String getCatalogName();
+
 }
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/catalog/api/PlanPhaseSpecifier.java b/api/src/main/java/com/ning/billing/catalog/api/PlanPhaseSpecifier.java
index 281a81c..4dcfa58 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/PlanPhaseSpecifier.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/PlanPhaseSpecifier.java
@@ -20,9 +20,9 @@ public class PlanPhaseSpecifier extends PlanSpecifier {
 
 	private final PhaseType phaseType;
 	
-	public PlanPhaseSpecifier(String productName, BillingPeriod billingPeriod,
+	public PlanPhaseSpecifier(String productName, ProductCategory productCategory, BillingPeriod billingPeriod,
 			String priceListName, PhaseType phaseType) {
-		super(productName, billingPeriod, priceListName);
+		super(productName, productCategory, billingPeriod, priceListName);
 		this.phaseType = phaseType;
 	}
 
diff --git a/api/src/main/java/com/ning/billing/catalog/api/PlanSpecifier.java b/api/src/main/java/com/ning/billing/catalog/api/PlanSpecifier.java
index face0da..92b6bc4 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/PlanSpecifier.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/PlanSpecifier.java
@@ -18,13 +18,15 @@ package com.ning.billing.catalog.api;
 
 public class PlanSpecifier {
 	private final String productName;
+	private final ProductCategory productCategory;
 	private final BillingPeriod billingPeriod;
 	private final String priceListName;
 	
-	public PlanSpecifier(String productName, BillingPeriod billingPeriod,
+	public PlanSpecifier(String productName, ProductCategory productCategory, BillingPeriod billingPeriod,
 			String priceListName) {
 		super();
 		this.productName = productName;
+		this.productCategory = productCategory;
 		this.billingPeriod = billingPeriod;
 		this.priceListName = priceListName;
 	}
@@ -32,6 +34,9 @@ public class PlanSpecifier {
 	public String getProductName() {
 		return productName;
 	}
+	public ProductCategory getProductCategory() {
+		return productCategory;
+	}
 	public BillingPeriod getBillingPeriod() {
 		return billingPeriod;
 	}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/CaseBillingAlignment.java b/catalog/src/main/java/com/ning/billing/catalog/CaseBillingAlignment.java
new file mode 100644
index 0000000..57dd49c
--- /dev/null
+++ b/catalog/src/main/java/com/ning/billing/catalog/CaseBillingAlignment.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import com.ning.billing.catalog.api.BillingAlignment;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.ProductCategory;
+
+public class CaseBillingAlignment extends CasePhase<BillingAlignment> {
+
+	@XmlElement(required=true)
+	private BillingAlignment alignment;
+
+	public CaseBillingAlignment() {}
+
+	public CaseBillingAlignment(Product product, ProductCategory productCategory, BillingPeriod billingPeriod,
+			PriceList priceList, PhaseType phaseType, BillingAlignment alignment) {
+		super(product, productCategory, billingPeriod, priceList, phaseType, alignment);
+		this.alignment = alignment;
+	}
+
+	@Override
+	protected BillingAlignment getResult() {
+		return alignment;
+	}
+}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/CaseCancelPolicy.java b/catalog/src/main/java/com/ning/billing/catalog/CaseCancelPolicy.java
new file mode 100644
index 0000000..700d6be
--- /dev/null
+++ b/catalog/src/main/java/com/ning/billing/catalog/CaseCancelPolicy.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import com.ning.billing.catalog.api.ActionPolicy;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.ProductCategory;
+
+public class CaseCancelPolicy extends CasePhase<ActionPolicy>{
+
+	@XmlElement(required=true)
+	private ActionPolicy policy;
+
+	public CaseCancelPolicy() {}
+
+	public CaseCancelPolicy(Product product, ProductCategory productCategory, BillingPeriod billingPeriod, PriceList priceList,
+			PhaseType phaseType, ActionPolicy policy) {
+		super(product, productCategory, billingPeriod, priceList, phaseType, policy);
+		this.policy = policy;
+	}
+
+
+
+	@Override
+	protected ActionPolicy getResult() {
+		return policy;
+	}
+
+}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/CaseChangePlanAlignment.java b/catalog/src/main/java/com/ning/billing/catalog/CaseChangePlanAlignment.java
new file mode 100644
index 0000000..a00ebb4
--- /dev/null
+++ b/catalog/src/main/java/com/ning/billing/catalog/CaseChangePlanAlignment.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.PlanAlignmentChange;
+import com.ning.billing.catalog.api.ProductCategory;
+
+public class CaseChangePlanAlignment extends CaseChange<PlanAlignmentChange> {
+
+	@XmlElement(required=true)
+	private PlanAlignmentChange alignment;
+	
+	public CaseChangePlanAlignment() {}
+
+	protected CaseChangePlanAlignment(
+			Product from, Product to, 
+			ProductCategory fromProductCategory, ProductCategory toProductCategory, 
+			BillingPeriod fromBP,BillingPeriod toBP, 
+			PriceList fromPriceList, PriceList toPriceList,
+			PhaseType fromType, 
+			PlanAlignmentChange result) {
+		super(from, to, 
+				fromProductCategory, toProductCategory, 
+				fromBP, toBP, 
+				fromPriceList, toPriceList,  
+				fromType,
+				result);
+		alignment = result;
+	}
+
+	@Override
+	protected PlanAlignmentChange getResult() {
+		return alignment;
+	}
+
+}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/CaseChangePlanPolicy.java b/catalog/src/main/java/com/ning/billing/catalog/CaseChangePlanPolicy.java
new file mode 100644
index 0000000..258b9cd
--- /dev/null
+++ b/catalog/src/main/java/com/ning/billing/catalog/CaseChangePlanPolicy.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
+
+import com.ning.billing.catalog.api.ActionPolicy;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.ProductCategory;
+
+@XmlSeeAlso(CaseChange.class)
+public class CaseChangePlanPolicy extends CaseChange<ActionPolicy> {
+	
+	@XmlElement(required=true)
+	private ActionPolicy policy;
+	
+	public CaseChangePlanPolicy() {}
+
+	protected CaseChangePlanPolicy(
+			Product from, Product to, 
+			ProductCategory fromProductCategory, ProductCategory toProductCategory, 
+			BillingPeriod fromBP,BillingPeriod toBP, 
+			PriceList fromPriceList, PriceList toPriceList,
+			PhaseType fromType,
+			ActionPolicy result) {
+		super(from, to, 
+				fromProductCategory, toProductCategory,
+				fromBP, toBP, 
+				fromPriceList, toPriceList, 
+				fromType, 
+				result);
+		policy = result;
+	}
+
+
+
+	@Override
+	protected ActionPolicy getResult() {
+		return policy;
+	}
+
+}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/CaseCreateAlignment.java b/catalog/src/main/java/com/ning/billing/catalog/CaseCreateAlignment.java
new file mode 100644
index 0000000..3a1ba1f
--- /dev/null
+++ b/catalog/src/main/java/com/ning/billing/catalog/CaseCreateAlignment.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.PlanAlignmentCreate;
+import com.ning.billing.catalog.api.ProductCategory;
+
+public class CaseCreateAlignment extends Case<PlanAlignmentCreate>{
+
+	@XmlElement(required=true)
+	private PlanAlignmentCreate alignment;
+
+	public CaseCreateAlignment() {}
+
+	public CaseCreateAlignment(Product product, ProductCategory productCategory,  BillingPeriod billingPeriod,
+			PriceList priceList, PlanAlignmentCreate alignment) {
+		super(product, productCategory, billingPeriod, priceList, alignment);
+		this.alignment = alignment;
+	}
+
+	@Override
+	protected PlanAlignmentCreate getResult() {
+		return alignment;
+	}
+
+}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/CasePhase.java b/catalog/src/main/java/com/ning/billing/catalog/CasePhase.java
new file mode 100644
index 0000000..e189c5c
--- /dev/null
+++ b/catalog/src/main/java/com/ning/billing/catalog/CasePhase.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import com.ning.billing.catalog.ValidatingConfig.ValidationErrors;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.ProductCategory;
+
+public abstract class CasePhase<T> extends Case<T> {
+
+	@XmlElement(required=false)
+	private PhaseType phaseType;
+
+	public CasePhase() {}
+
+	public CasePhase(Product product, ProductCategory productCategory,
+			BillingPeriod billingPeriod, PriceList priceList,
+			PhaseType phaseType, T result) {
+		super(product, productCategory, billingPeriod, priceList, result);
+		this.phaseType = phaseType;
+	}
+	
+	
+	public T getResult(PlanPhaseSpecifier planPhase, Catalog c) {
+		if (	
+				(phaseType       == null || planPhase.getPhaseType() == null || planPhase.getPhaseType() == phaseType) &&
+				satisfiesCase(planPhase, c)
+				) {
+			return getResult(); 
+		}
+		return null;
+	}
+	
+	public static <K> K getResult(Case<K>[] cases, PlanPhaseSpecifier planSpec, Catalog catalog) {
+    	if(cases != null) {
+    		for(int i = cases.length - 1; i >=0; i --) {
+    			K result = cases[i].getResult(planSpec, catalog);
+    			if(result != null) { 
+    				return result; 
+    			}        					
+    		}
+    	}
+        return null;
+        
+    }
+
+	@Override
+	public ValidationErrors validate(Catalog catalog, ValidationErrors errors) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/Catalog.java b/catalog/src/main/java/com/ning/billing/catalog/Catalog.java
index 0618c8e..c83da21 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/Catalog.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/Catalog.java
@@ -17,9 +17,7 @@
 package com.ning.billing.catalog;
 
 import java.net.URL;
-import java.util.ArrayList;
 import java.util.Date;
-import java.util.List;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
@@ -28,33 +26,39 @@ import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlRootElement;
 
 import com.ning.billing.catalog.api.ActionPolicy;
+import com.ning.billing.catalog.api.BillingAlignment;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.catalog.api.ICatalog;
-import com.ning.billing.catalog.api.IPlan;
 import com.ning.billing.catalog.api.IProduct;
-import com.ning.billing.catalog.api.IProductType;
-import com.ning.billing.catalog.api.PlanAlignment;
+import com.ning.billing.catalog.api.PlanAlignmentChange;
+import com.ning.billing.catalog.api.PlanAlignmentCreate;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PlanSpecifier;
 
 @XmlRootElement
 @XmlAccessorType(XmlAccessType.NONE)
 public class Catalog extends ValidatingConfig implements ICatalog {
+	public PlanRules getPlanRules() {
+		return planRules;
+	}
+
+	public void setPlanRules(PlanRules planRules) {
+		this.planRules = planRules;
+	}
 
 	@XmlElement(required=true)
 	private Date effectiveDate;
 
+	@XmlElement(required=true)
+	private String catalogName;
+
 	private URL catalogURL;
 
 	@XmlElementWrapper(name="currencies", required=true)
 	@XmlElement(name="currency", required=true)
 	private Currency[] supportedCurrencies;
 
-	@XmlElementWrapper(name="productTypes", required=true)
-	@XmlElement(name="productType", required=true)
-    private ProductType[] productTypes;
-
 	@XmlElementWrapper(name="products", required=true)
 	@XmlElement(name="product", required=true)
 	private Product[] products;
@@ -93,12 +97,12 @@ public class Catalog extends ValidatingConfig implements ICatalog {
 	}
 
     /* (non-Javadoc)
-	 * @see com.ning.billing.catalog.ICatalog#getProductTypes()
+	 * @see com.ning.billing.catalog.ICatalog#getCalalogName()
 	 */
     @Override
-	public ProductType[] getProductTypes() {
-        return productTypes;
-    }
+	public String getCalalogName() {
+		return catalogName;
+	}
 
     /* (non-Javadoc)
 	 * @see com.ning.billing.catalog.ICatalog#getProducts()
@@ -138,20 +142,6 @@ public class Catalog extends ValidatingConfig implements ICatalog {
     }
 
     /* (non-Javadoc)
-	 * @see com.ning.billing.catalog.ICatalog#getProductsForType(com.ning.billing.catalog.ProductType)
-	 */
-    @Override
-	public List<IProduct> getProductsForType(IProductType productType) {
-    	ArrayList<IProduct> result = new ArrayList<IProduct>();
-    	for(Product p : products) {
-			if(p.getType().equals(productType)) {
-				result.add(p);
-			}
-		}
-        return result;
-    }
-
-    /* (non-Javadoc)
 	 * @see com.ning.billing.catalog.ICatalog#getPlan(java.lang.String, java.lang.String)
 	 */
     @Override
@@ -171,10 +161,6 @@ public class Catalog extends ValidatingConfig implements ICatalog {
         return null;
     }
 
-	public void setProductTypes(ProductType[] productTypes) {
-		this.productTypes = productTypes;
-	}
-
 	@Override
 	public Currency[] getSupportedCurrencies() {
 		return supportedCurrencies;
@@ -200,7 +186,6 @@ public class Catalog extends ValidatingConfig implements ICatalog {
 	@Override
 	public ValidationErrors validate(Catalog catalog, ValidationErrors errors) {
 		errors.addAll(validate(catalog,errors, products));
-		errors.addAll(validate(catalog,errors, productTypes));
 		errors.addAll(validate(catalog,errors, priceLists));
 		errors.addAll(validate(catalog,errors, plans));
 		errors.addAll(planRules.validate(catalog, errors));
@@ -211,6 +196,11 @@ public class Catalog extends ValidatingConfig implements ICatalog {
     public ActionPolicy getPlanChangePolicy(PlanPhaseSpecifier from, PlanSpecifier to) {
         return planRules.getPlanChangePolicy(from, to, this);
     }
+    
+    @Override
+    public PlanAlignmentChange getPlanChangeAlignment(PlanPhaseSpecifier from, PlanSpecifier to) {
+        return planRules.getPlanChangeAlignment(from, to, this);
+    }
 
     @Override
     public ActionPolicy getPlanCancelPolicy(PlanPhaseSpecifier planPhase) {
@@ -218,12 +208,20 @@ public class Catalog extends ValidatingConfig implements ICatalog {
     }
     
     @Override
-    public PlanAlignment getPlanAlignment(PlanPhaseSpecifier from, PlanSpecifier to) {
-        return planRules.getPlanAlignment(from, to, this);
+    public PlanAlignmentCreate getPlanCreateAlignment(PlanSpecifier planPhase) {
+    	PlanPhaseSpecifier specifier = new PlanPhaseSpecifier(planPhase.getProductName(), planPhase.getProductCategory(), planPhase.getBillingPeriod(), planPhase.getPriceListName(), null);
+    	
+        return planRules.getPlanCreateAlignment(specifier, this);
     }
+    
+    @Override
+    public BillingAlignment getBillingAlignment(PlanPhaseSpecifier planPhase) {
+        return planRules.getBillingAlignment(planPhase, this);
+    }
+
 
     @Override
-    public IPlan getPlanFromName(String name) {
+    public Plan getPlanFromName(String name) {
         if (name == null) {
             return null;
         }
@@ -297,6 +295,12 @@ public class Catalog extends ValidatingConfig implements ICatalog {
 	public void setPriceLists(PriceList[] priceLists) {
 		this.priceLists = priceLists;
 	}
+
+	@Override
+	public void configureEffectiveDate(Date date) {
+		// Nothing to do here this is a method that is only inplemented on VersionedCatalog
+		
+	}
 	
 	//TODO: MDW validation - only allow one default pricelist
 
diff --git a/catalog/src/main/java/com/ning/billing/catalog/ICatalogConfiguration.java b/catalog/src/main/java/com/ning/billing/catalog/ICatalogConfiguration.java
new file mode 100644
index 0000000..394802d
--- /dev/null
+++ b/catalog/src/main/java/com/ning/billing/catalog/ICatalogConfiguration.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog;
+
+import org.skife.config.Config;
+
+public interface ICatalogConfiguration {
+	
+    @Config("killbill.catalog.config.directory")
+    public String getCatalogDirectoryURL();
+
+}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/io/ICatalogLoader.java b/catalog/src/main/java/com/ning/billing/catalog/io/ICatalogLoader.java
new file mode 100644
index 0000000..426f7c6
--- /dev/null
+++ b/catalog/src/main/java/com/ning/billing/catalog/io/ICatalogLoader.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog.io;
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.xml.bind.JAXBException;
+
+import org.xml.sax.SAXException;
+
+import com.ning.billing.catalog.VersionedCatalog;
+import com.ning.billing.catalog.api.InvalidConfigException;
+
+public interface ICatalogLoader {
+
+	public abstract VersionedCatalog load(URL url) throws IOException,
+			SAXException, InvalidConfigException, JAXBException;
+
+}
\ No newline at end of file
diff --git a/catalog/src/main/java/com/ning/billing/catalog/io/VersionedCatalogLoader.java b/catalog/src/main/java/com/ning/billing/catalog/io/VersionedCatalogLoader.java
index 9c795cb..59bffa3 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/io/VersionedCatalogLoader.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/io/VersionedCatalogLoader.java
@@ -33,13 +33,17 @@ import com.ning.billing.catalog.Catalog;
 import com.ning.billing.catalog.VersionedCatalog;
 import com.ning.billing.catalog.api.InvalidConfigException;
 
-public class VersionedCatalogLoader {
-	private static final String XML_EXTENSION = ".xml";
-	private static final String HREF_LOW_START = "href=\""; 
-	private static final String HREF_CAPS_START = "HREF=\""; 
-	private static final String HREF_SEARCH_END = "\"";
+public class VersionedCatalogLoader implements ICatalogLoader {
+	private  final String XML_EXTENSION = ".xml";
+	private  final String HREF_LOW_START = "href=\""; 
+	private  final String HREF_CAPS_START = "HREF=\""; 
+	private  final String HREF_SEARCH_END = "\"";
 		
-	public static VersionedCatalog load(URL url) throws IOException, SAXException, InvalidConfigException, JAXBException {
+	/* (non-Javadoc)
+	 * @see com.ning.billing.catalog.io.ICatalogLoader#load(java.net.URL)
+	 */
+	@Override
+	public  VersionedCatalog load(URL url) throws IOException, SAXException, InvalidConfigException, JAXBException {
 		String directoryContents = pullContentsFrom(url);
 		List<URL> xmlURLs = findXmlReferences(directoryContents, url);
 		VersionedCatalog result = new VersionedCatalog();
@@ -50,14 +54,14 @@ public class VersionedCatalogLoader {
 		return result;
 	}
 	
-	protected static List<URL> findXmlReferences(String directoryContents, URL url) throws MalformedURLException {
+	protected  List<URL> findXmlReferences(String directoryContents, URL url) throws MalformedURLException {
 		if(url.getProtocol().equals("file")) {
 			return findXmlFileReferences(directoryContents, url);
 		} 
 		return findXmlUrlReferences(directoryContents, url);
 	}
 
-	protected static List<URL> findXmlUrlReferences(String directoryContents, URL url) throws MalformedURLException {
+	protected  List<URL> findXmlUrlReferences(String directoryContents, URL url) throws MalformedURLException {
 		List<URL> results = new ArrayList<URL>();
 		List<String> urlFragments = extractHrefs(directoryContents);
 		for(String u : urlFragments) {
@@ -74,7 +78,7 @@ public class VersionedCatalogLoader {
 		return results;
 	}
 
-	protected static List<String> extractHrefs(String directoryContents) {
+	protected  List<String> extractHrefs(String directoryContents) {
 		List<String> results = new ArrayList<String>();
 		int start = 0;
 		int end = 0;
@@ -102,7 +106,7 @@ public class VersionedCatalogLoader {
 		return results;
 	}
 
-	protected static List<URL> findXmlFileReferences(String directoryContents, URL url) throws MalformedURLException {
+	protected  List<URL> findXmlFileReferences(String directoryContents, URL url) throws MalformedURLException {
 		List<URL> results = new ArrayList<URL>();
 		String[] filenames = directoryContents.split("\\n");
 		for(String filename : filenames) {
@@ -113,7 +117,7 @@ public class VersionedCatalogLoader {
 		return results;
 	}
 
-	protected static URL appendToURL(final URL url, final String filename) throws MalformedURLException {
+	protected  URL appendToURL(final URL url, final String filename) throws MalformedURLException {
 		String f = filename;
 		if (!url.toString().endsWith("/")) {
 			f = "/" + filename;
@@ -121,14 +125,9 @@ public class VersionedCatalogLoader {
 		return new URL(url.toString() + f);
 	}
 
-	protected static String pullContentsFrom(final URL url) throws IOException {
+	protected  String pullContentsFrom(final URL url) throws IOException {
 		URLConnection connection = url.openConnection();
 		InputStream content = connection.getInputStream();
 		return new Scanner(content).useDelimiter("\\A").next();
 	}
-	
-	public static void main (String[] args) throws Exception {		
-		//new VersionedCatalog().initialize(new URL("http://gepo.ningops.net/config/trunk/xno/viking/master/viking-core/"));
-		new VersionedCatalogLoader().load(new URL("file:///Users/mwesthead/work/killbill/catalog/src/test/resources/"));
-	}
 }
diff --git a/catalog/src/main/java/com/ning/billing/catalog/io/XMLReader.java b/catalog/src/main/java/com/ning/billing/catalog/io/XMLReader.java
index 1d77249..1f568ea 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/io/XMLReader.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/io/XMLReader.java
@@ -16,8 +16,6 @@
 
 package com.ning.billing.catalog.io;
 
-import java.io.File;
-import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
 
@@ -25,7 +23,6 @@ import javax.xml.XMLConstants;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
-import javax.xml.transform.TransformerException;
 import javax.xml.transform.stream.StreamSource;
 import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
@@ -33,12 +30,6 @@ import javax.xml.validation.SchemaFactory;
 import org.xml.sax.SAXException;
 
 import com.ning.billing.catalog.Catalog;
-import com.ning.billing.catalog.Duration;
-import com.ning.billing.catalog.Plan;
-import com.ning.billing.catalog.PlanPhase;
-import com.ning.billing.catalog.PriceList;
-import com.ning.billing.catalog.Product;
-import com.ning.billing.catalog.ProductType;
 import com.ning.billing.catalog.ValidatingConfig.ValidationErrors;
 import com.ning.billing.catalog.api.InvalidConfigException;
 
@@ -46,7 +37,7 @@ public class XMLReader {
 
 
     public static Catalog getCatalogFromName(URL url) throws SAXException, InvalidConfigException, JAXBException {
-        JAXBContext context =JAXBContext.newInstance(Catalog.class,Plan.class,Duration.class, Product.class, ProductType.class, PlanPhase.class, PriceList.class);
+        JAXBContext context =JAXBContext.newInstance(Catalog.class);
 
         InputStream resourceStream = XMLReader.class.getResourceAsStream("/CatalogSchema.xsd");
         SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI );
@@ -68,17 +59,5 @@ public class XMLReader {
             return null;
         }
     }
-	/**
-	 * @param args
-	 * @throws SAXException
-	 * @throws InvalidConfigException
-	 */
-	public static void main(String[] args) throws IOException, TransformerException, JAXBException, SAXException, InvalidConfigException {
-		String curDir = System.getProperty("user.dir");
-		getCatalogFromName(new File("src/test/resources/WeaponsHire.xml").toURI().toURL());
-		getCatalogFromName(new File("src/test/resources/WeaponsHireSmall.xml").toURI().toURL());
-
-	}
-	
 	
 }
diff --git a/catalog/src/main/java/com/ning/billing/catalog/io/XMLSchemaGenerator.java b/catalog/src/main/java/com/ning/billing/catalog/io/XMLSchemaGenerator.java
index c28eccc..ae41c61 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/io/XMLSchemaGenerator.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/io/XMLSchemaGenerator.java
@@ -37,17 +37,12 @@ import javax.xml.transform.stream.StreamResult;
 import org.w3c.dom.Document;
 
 import com.ning.billing.catalog.Catalog;
-import com.ning.billing.catalog.Duration;
-import com.ning.billing.catalog.Plan;
-import com.ning.billing.catalog.PlanPhase;
-import com.ning.billing.catalog.PriceList;
-import com.ning.billing.catalog.Product;
-import com.ning.billing.catalog.ProductType;
 
 public class XMLSchemaGenerator {
 
+	//Note: this main method is called byt the maven build to generate the schema for the jar
 	public static void main(String[] args) throws IOException, TransformerException, JAXBException {
-		JAXBContext context =JAXBContext.newInstance(Catalog.class,Plan.class,Duration.class, Product.class, ProductType.class, PlanPhase.class, PriceList.class);
+		JAXBContext context =JAXBContext.newInstance(Catalog.class);
 		String xsdFileName = "CatalogSchema.xsd";
 		if(args.length != 0) {
 			xsdFileName = args[0] + "/" + xsdFileName;
diff --git a/catalog/src/main/java/com/ning/billing/catalog/Plan.java b/catalog/src/main/java/com/ning/billing/catalog/Plan.java
index 10e80aa..a220cf7 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/Plan.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/Plan.java
@@ -52,9 +52,6 @@ public class Plan extends ValidatingConfig implements IPlan {
 	@XmlElement(name="finalPhase", required=true)
     private PlanPhase finalPhase;
 	
-	@XmlElement(required=true)
-	private BillingAlignment billingAlignment;
-
 	//If this is missing it defaults to 1
 	//No other value is allowed for BASE plans.
 	//No other value is allowed for Tiered ADDONS
@@ -135,7 +132,6 @@ public class Plan extends ValidatingConfig implements IPlan {
 	@Override
 	public ValidationErrors validate(Catalog catalog, ValidationErrors errors) {
 		return errors;
-		
 	}
 	
 	@Override
@@ -153,18 +149,6 @@ public class Plan extends ValidatingConfig implements IPlan {
 	}
 
 	/* (non-Javadoc)
-	 * @see com.ning.billing.catalog.IPlan#getBillingAlignment()
-	 */
-	@Override
-	public BillingAlignment getBillingAlignment() {
-		return billingAlignment;
-	}
-
-	public void setBillingAlignment(BillingAlignment billingAlignment) {
-		this.billingAlignment = billingAlignment;
-	}
-
-	/* (non-Javadoc)
 	 * @see com.ning.billing.catalog.IPlan#getPlansAllowedInBundle()
 	 */
 	@Override
diff --git a/catalog/src/main/java/com/ning/billing/catalog/PlanRules.java b/catalog/src/main/java/com/ning/billing/catalog/PlanRules.java
index 2d742a2..34b372f 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/PlanRules.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/PlanRules.java
@@ -22,9 +22,11 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 
 import com.ning.billing.catalog.api.ActionPolicy;
+import com.ning.billing.catalog.api.BillingAlignment;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.IProduct;
-import com.ning.billing.catalog.api.PlanAlignment;
+import com.ning.billing.catalog.api.PlanAlignmentChange;
+import com.ning.billing.catalog.api.PlanAlignmentCreate;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PlanSpecifier;
 
@@ -35,63 +37,62 @@ public class PlanRules extends ValidatingConfig  {
 	@XmlElement(name="tier", required=false) // may not have tiers in some catalogs
 	private ProductTier[] productTiers;
 
-	@XmlElement(name="changeRule", required=true)
-	private PlanChangeRule[] rules;
+	@XmlElement(name="changePolicyRule", required=true)
+	private PlanPolicyChangeRule[] rules;
 
-	@XmlElement(name="changeCase", required=false)
-	private PlanChangeCase[] changeCase;
+	@XmlElement(name="changePolicyCase", required=false)
+	private CaseChangePlanPolicy[] changeCase;
 	
-	@XmlElement(name="cancelCase", required=false)
-	private PlanCancelCase[] cancelCase;
+	@XmlElement(name="changeAlignmentCase", required=false)
+	private CaseChangePlanAlignment[] changeAlignmentCase;
 
-	@XmlElement(name="alignmentCase", required=false)
-	private PlanAlignmentCase[] alignmentCase;
+	@XmlElement(name="cancelPolicyCase", required=false)
+	private CaseCancelPolicy[] cancelCase;
 
-	public PlanChangeRule[] getRules() {
-		return rules;
-	}
-
-	public void setGeneralRules(PlanChangeRule[] generalRules) {
-		this.rules = generalRules;
-	}
-
-	public PlanChangeCase[] getSpecialCase() {
-		return changeCase;
-	}
-
-	protected void setSpecialCaseRules(PlanChangeCase[] specialchangeCaseCaseRules) {
-		this.changeCase = specialchangeCaseCaseRules;
-	}
-	
-	protected void setCancelCaseRules(PlanCancelCase[] cancelCase) {
-		this.cancelCase = cancelCase;
-	}
+	@XmlElement(name="createAlignmentCase", required=false)
+	private CaseCreateAlignment[] createAlignmentCase;
 	
-	public void setAlignmentCase(PlanAlignmentCase[] alignmentCase) {
-		this.alignmentCase = alignmentCase;
-	}
+	@XmlElement(name="billingAlignmentCase", required=false)
+	private CaseBillingAlignment[] billingAlignmentCase;
 
 	@Override
 	public ValidationErrors validate(Catalog catalog, ValidationErrors errors) {
 		return errors;
 
 	}
+	
+	public PlanRules(){}
+
+	//For test
+	protected PlanRules(ProductTier[] productTiers, PlanPolicyChangeRule[] rules,
+			CaseChangePlanPolicy[] changeCase, CaseCancelPolicy[] cancelCase,
+			CaseChangePlanAlignment[] changeAlignmentCase,
+			CaseCreateAlignment[] createAlignmentCase) {
+		super();
+		this.productTiers = productTiers;
+		this.rules = rules;
+		this.changeCase = changeCase;
+		this.cancelCase = cancelCase;
+		this.changeAlignmentCase = changeAlignmentCase;
+		this.createAlignmentCase = createAlignmentCase;
+	}
 
 	public ActionPolicy getPlanChangePolicy(PlanPhaseSpecifier from,
 			PlanSpecifier to, Catalog catalog) {
-    	if(changeCase != null) {
-    		for(int i = changeCase.length - 1; i >=0; i --) {
-    			ActionPolicy policy = changeCase[i].getPlanChangePolicy(from, to, catalog);
-    			if (policy != null) { return policy; }        					
-    		}
-    	}
+		
+		ActionPolicy policy = CaseChange.getResult(changeCase, from, to, catalog); 
+		if (policy != null) {
+			return policy;
+		}
+
+    	
         for(int i = rules.length - 1; i >=0; i --) {
         	int fromProductIndex       = getProductIndex(catalog.getProductFromName(from.getProductName()));
         	int fromBillingPeriodIndex = getBillingPeriodIndex(from.getBillingPeriod());
 			int toProductIndex         = getProductIndex(catalog.getProductFromName(to.getProductName()));
 			int toBillingPeriodIndex   = getBillingPeriodIndex(to.getBillingPeriod());
 			
-        	ActionPolicy policy = rules[i].getPlanChangePolicy(
+			policy = rules[i].getPlanChangePolicy(
         		fromProductIndex, fromBillingPeriodIndex,
         		toProductIndex, toBillingPeriodIndex,
         		from.getPhaseType());
@@ -100,39 +101,7 @@ public class PlanRules extends ValidatingConfig  {
         return null;
         
     }
-
-	public PlanAlignment getPlanAlignment(PlanPhaseSpecifier from,
-			PlanSpecifier to, Catalog catalog) {
-    	if(alignmentCase != null) {
-    		for(int i = alignmentCase.length - 1; i >=0; i --) {
-    			PlanAlignment alignment = alignmentCase[i].getPlanAlignment(from, to, catalog);
-    			if(alignment != null) { 
-    				return alignment; 
-    			}        					
-    		}
-    	}
-        return null;
-        
-    }
-
 	
-	public ActionPolicy getPlanCancelPolicy(PlanPhaseSpecifier planPhase, Catalog catalog) {
-    	if(cancelCase != null) {
-    		for(int i = cancelCase.length - 1; i >=0; i --) {
-    			ActionPolicy policy = cancelCase[i].getPlanCancelPolicy(planPhase, catalog);
-    			if (policy != null) { 
-    				return policy; 
-    			}        					
-    		}
-    	}
-
-		return null;
-	}
-
-	private int getBillingPeriodIndex(BillingPeriod src) {
-		return src.ordinal();
-	}
-
 	private int getProductIndex(IProduct src) {
 		for(ProductTier tier : productTiers) {
 			for(int i = 0; i < tier.getProducts().length; i++ ){
@@ -143,12 +112,34 @@ public class PlanRules extends ValidatingConfig  {
 		}
 		return 0;
 	}
+	public PlanAlignmentChange getPlanChangeAlignment(PlanPhaseSpecifier from,
+			PlanSpecifier to, Catalog catalog) {
+		return CaseChange.getResult(changeAlignmentCase, from, to, catalog);      
+    }
+
+	public PlanAlignmentCreate getPlanCreateAlignment(PlanPhaseSpecifier planPhase, Catalog catalog) {
+		return Case.getResult(createAlignmentCase, planPhase, catalog);      
+    }
+	
+	public ActionPolicy getPlanCancelPolicy(PlanPhaseSpecifier planPhase, Catalog catalog) {
+		return Case.getResult(cancelCase, planPhase, catalog);      
+	}
+
+	public BillingAlignment getBillingAlignment(PlanPhaseSpecifier planPhase, Catalog catalog) {
+		return Case.getResult(billingAlignmentCase, planPhase, catalog);      
+	}
+
+	private int getBillingPeriodIndex(BillingPeriod src) {
+		return src.ordinal();
+	}
+
 
 	protected void setProductTiers(ProductTier[] productTiers) {
 		this.productTiers = productTiers;
 	}
 
 
+
 	
     //TODO: MDW - Validation: check that the plan change special case pairs are unique!
     //TODO: MDW - Validation: check that the each product appears in at most one tier.
diff --git a/catalog/src/main/java/com/ning/billing/catalog/Product.java b/catalog/src/main/java/com/ning/billing/catalog/Product.java
index 253fe1e..310837c 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/Product.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/Product.java
@@ -25,19 +25,15 @@ import javax.xml.bind.annotation.XmlID;
 import javax.xml.bind.annotation.XmlIDREF;
 
 import com.ning.billing.catalog.api.IProduct;
-import com.ning.billing.catalog.api.IProductType;
 import com.ning.billing.catalog.api.ProductCategory;
 
 @XmlAccessorType(XmlAccessType.NONE)
 public class Product extends ValidatingConfig implements IProduct {
-
+	
 	@XmlAttribute (required=true)
 	@XmlID
     private String name;
 
-	@XmlIDREF @XmlElement(required=true)
-    private ProductType type;
-
 	@XmlElement(required=true)
     private ProductCategory category;
 	
@@ -48,8 +44,17 @@ public class Product extends ValidatingConfig implements IProduct {
 	@XmlElementWrapper(name="available", required=false)
 	@XmlIDREF @XmlElement(name="addonProduct", required=true)
     private Product[] available;
+
+	//Not included in XML
+	private String catalogName;
+	
 	
 	@Override
+	public String getCatalogName() {
+		return catalogName;
+	}
+
+	@Override
     public ProductCategory getCategory() {
 		return category;
 	}
@@ -67,13 +72,9 @@ public class Product extends ValidatingConfig implements IProduct {
 	public Product() {
     }
 
-    protected Product(IProductType type, String name) {
-    	this.name = name;
-    }
-
-    @Override
-	public ProductType getType() {
-        return type;
+	protected Product(String name, ProductCategory category) {
+		this.category = category;
+		this.name = name;
     }
 
     @Override
@@ -81,10 +82,6 @@ public class Product extends ValidatingConfig implements IProduct {
         return name;
     }
 
-	public void setType(ProductType type) {
-		this.type = type;
-	}
-
 	public void setName(String name) {
 		this.name = name;
 	}
@@ -115,6 +112,12 @@ public class Product extends ValidatingConfig implements IProduct {
 		}
 		return false;
 	}
+	
+	@Override
+	public void initialize(Catalog catalog) {
+		catalogName = catalog.getCalalogName();
+	}
+
 
 	//TODO: MDW validation: inclusion and exclusion lists can only contain addon products
 	//TODO: MDW validation: a given product can only be in, at most, one of inclusion and exclusion lists
diff --git a/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
index d4aa4c6..055ccd7 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
@@ -23,14 +23,14 @@ import java.util.Iterator;
 import java.util.List;
 
 import com.ning.billing.catalog.api.ActionPolicy;
+import com.ning.billing.catalog.api.BillingAlignment;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.catalog.api.ICatalog;
-import com.ning.billing.catalog.api.IPlan;
 import com.ning.billing.catalog.api.IPlanPhase;
 import com.ning.billing.catalog.api.IProduct;
-import com.ning.billing.catalog.api.IProductType;
-import com.ning.billing.catalog.api.PlanAlignment;
+import com.ning.billing.catalog.api.PlanAlignmentChange;
+import com.ning.billing.catalog.api.PlanAlignmentCreate;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PlanSpecifier;
 
@@ -74,7 +74,8 @@ public class VersionedCatalog extends ValidatingConfig implements ICatalog {
 		return versions.iterator();
 	}
 	
-	public void applyEffectiveDate(Date date) {
+	@Override
+	public void configureEffectiveDate(Date date) {
 		currentCatalog = versionForDate(date); // 
 	}
 
@@ -82,93 +83,58 @@ public class VersionedCatalog extends ValidatingConfig implements ICatalog {
 		return versions.size();
 	}
 
-	public boolean equals(Object arg0) {
-		return currentCatalog.equals(arg0);
-	}
-
-	public ProductType[] getProductTypes() {
-		return currentCatalog.getProductTypes();
-	}
-
+	@Override
 	public Product[] getProducts() {
 		return currentCatalog.getProducts();
 	}
 
-	public void setProducts(Product[] products) {
-		currentCatalog.setProducts(products);
-	}
-
+	@Override
 	public PriceList[] getPriceLists() {
 		return currentCatalog.getPriceLists();
 	}
 
-	public void setPlanSets(PriceList[] planSets) {
-		currentCatalog.setPlanSets(planSets);
-	}
-
+	@Override
 	public PriceList getPriceListFromName(String planSetName) {
 		return currentCatalog.getPriceListFromName(planSetName);
 	}
 
-	public List<IProduct> getProductsForType(IProductType productType) {
-		return currentCatalog.getProductsForType(productType);
-	}
-
+	@Override
 	public Plan getPlan(String productName, BillingPeriod term,
 			String planSetName) {
 		return currentCatalog.getPlan(productName, term, planSetName);
 	}
 
-	public void setProductTypes(ProductType[] productTypes) {
-		currentCatalog.setProductTypes(productTypes);
-	}
-
+	@Override
 	public Currency[] getSupportedCurrencies() {
 		return currentCatalog.getSupportedCurrencies();
 	}
 
+	@Override
 	public Plan[] getPlans() {
 		return currentCatalog.getPlans();
 	}
 
-	public IPlan getPlanFromName(String name) {
+	@Override
+	public Plan getPlanFromName(String name) {
 		return currentCatalog.getPlanFromName(name);
 	}
 
+
+	@Override
 	public IPlanPhase getPhaseFromName(String name) {
 		return currentCatalog.getPhaseFromName(name);
 	}
 
+	@Override
 	public Date getEffectiveDate() {
 		return currentCatalog.getEffectiveDate();
 	}
 
-	public int hashCode() {
-		return currentCatalog.hashCode();
-	}
-
+	@Override
 	public void initialize(Catalog catalog) {
-		currentCatalog.initialize(catalog);
-	}
-
-	public void setSupportedCurrencies(Currency[] supportedCurrencies) {
-		currentCatalog.setSupportedCurrencies(supportedCurrencies);
-	}
-
-	public void setPlanChangeRules(PlanRules planChangeRules) {
-		currentCatalog.setPlanChangeRules(planChangeRules);
-	}
-
-	public void setPlans(Plan[] plans) {
-		currentCatalog.setPlans(plans);
-	}
-
-	public void setEffectiveDate(Date effectiveDate) {
-		currentCatalog.setEffectiveDate(effectiveDate);
-	}
-
-	public String toString() {
-		return currentCatalog.toString();
+		for(Catalog c : versions) {
+			c.initialize(catalog);
+		}
 	}
 
 	@Override
@@ -202,9 +168,27 @@ public class VersionedCatalog extends ValidatingConfig implements ICatalog {
 	}
 
 	@Override
-	public PlanAlignment getPlanAlignment(PlanPhaseSpecifier from,
+	public PlanAlignmentChange getPlanChangeAlignment(PlanPhaseSpecifier from,
 			PlanSpecifier to) {
-		return currentCatalog.getPlanAlignment(from, to);
+		return currentCatalog.getPlanChangeAlignment(from, to);
+	}
+
+	@Override
+	public PlanAlignmentCreate getPlanCreateAlignment(PlanSpecifier specifier) {
+		return currentCatalog.getPlanCreateAlignment(specifier);
+	}
+
+	@Override
+	public String getCalalogName() {
+		return currentCatalog.getCalalogName();
+	}
+
+	@Override
+	public BillingAlignment getBillingAlignment(PlanPhaseSpecifier planPhase) {
+		return currentCatalog.getBillingAlignment(planPhase);
 	}
+	
+	//TODO MDW validation - ensure all catalog versions have a single name
+	//TODO MDW validation - ensure effective dates are different (actually do we want this?)
  
 }
diff --git a/catalog/src/test/java/com/ning/billing/catalog/io/TestVersionedCatalogLoader.java b/catalog/src/test/java/com/ning/billing/catalog/io/TestVersionedCatalogLoader.java
index 1e978a2..c8efd11 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/io/TestVersionedCatalogLoader.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/io/TestVersionedCatalogLoader.java
@@ -15,12 +15,6 @@
  */
 package com.ning.billing.catalog.io;
 
-import static com.ning.billing.catalog.io.VersionedCatalogLoader.appendToURL;
-import static com.ning.billing.catalog.io.VersionedCatalogLoader.extractHrefs;
-import static com.ning.billing.catalog.io.VersionedCatalogLoader.findXmlFileReferences;
-import static com.ning.billing.catalog.io.VersionedCatalogLoader.findXmlUrlReferences;
-import static com.ning.billing.catalog.io.VersionedCatalogLoader.load;
-import static com.ning.billing.catalog.io.VersionedCatalogLoader.pullContentsFrom;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertTrue;
 
@@ -28,7 +22,6 @@ import java.io.File;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 
@@ -43,11 +36,12 @@ import com.ning.billing.catalog.VersionedCatalog;
 import com.ning.billing.catalog.api.InvalidConfigException;
 
 public class TestVersionedCatalogLoader {
+	private final VersionedCatalogLoader loader = new VersionedCatalogLoader();
 
 
 	@Test(enabled=true)
 	public void testPullContentsFrom() throws MalformedURLException, IOException {
-		String contents = pullContentsFrom(new File("src/test/resources/WeaponsHireSmall.xml").toURI().toURL());
+		String contents = loader.pullContentsFrom(new File("src/test/resources/WeaponsHireSmall.xml").toURI().toURL());
 
 		assertTrue(contents.length() > 0);
 		
@@ -56,10 +50,10 @@ public class TestVersionedCatalogLoader {
 	@Test(enabled=true)
 	public void testAppendToURL() throws MalformedURLException, IOException {
 		URL u1 = new URL("http://www.ning.com/foo");
-		assertEquals("http://www.ning.com/foo/bar",appendToURL(u1, "bar").toString());
+		assertEquals("http://www.ning.com/foo/bar",loader.appendToURL(u1, "bar").toString());
 
 		URL u2 = new URL("http://www.ning.com/foo/");
-		assertEquals("http://www.ning.com/foo/bar",appendToURL(u2, "bar").toString());
+		assertEquals("http://www.ning.com/foo/bar",loader.appendToURL(u2, "bar").toString());
 		
 	}
 	
@@ -72,7 +66,7 @@ public class TestVersionedCatalogLoader {
 				"replica.foo\n" + 
 				"snv1/\n" + 
 				"viking.xml\n" ;
-		List<URL> urls = findXmlFileReferences(page, new URL("http://ning.com/"));
+		List<URL> urls = loader.findXmlFileReferences(page, new URL("http://ning.com/"));
 		assertEquals(2, urls.size());
 		assertEquals("http://ning.com/dg.xml", urls.get(0).toString());
 		assertEquals("http://ning.com/viking.xml", urls.get(1).toString());
@@ -98,7 +92,7 @@ public class TestVersionedCatalogLoader {
 				"</ul>" + 
 				"<address>Apache/2.2.3 (CentOS) Server at <a href=\"mailto:kate@ning.com\">gepo.ningops.net</a> Port 80</address>" + 
 				"</body></html>" ;
-		List<String> hrefs = extractHrefs(page);
+		List<String> hrefs = loader.extractHrefs(page);
 		assertEquals(8, hrefs.size());
 		assertEquals("/config/trunk/", hrefs.get(0));
 		assertEquals("dg.xml", hrefs.get(1));
@@ -123,7 +117,7 @@ public class TestVersionedCatalogLoader {
 				"</ul>" + 
 				"<address>Apache/2.2.3 (CentOS) Server at <a href=\"mailto:kate@ning.com\">gepo.ningops.net</a> Port 80</address>" + 
 				"</body></html>" ;
-		List<URL> urls = findXmlUrlReferences(page, new URL("http://ning.com/"));
+		List<URL> urls = loader.findXmlUrlReferences(page, new URL("http://ning.com/"));
 		assertEquals(2, urls.size());
 		assertEquals("http://ning.com/dg.xml", urls.get(0).toString());
 		assertEquals("http://ning.com/viking.xml", urls.get(1).toString());
@@ -132,7 +126,7 @@ public class TestVersionedCatalogLoader {
 	
 	@Test(enabled=true)
 	public void testLoad() throws MalformedURLException, IOException, SAXException, InvalidConfigException, JAXBException {
-		VersionedCatalog c = load(new File("src/test/resources/versionedCatalog").toURI().toURL());
+		VersionedCatalog c = loader.load(new File("src/test/resources/versionedCatalog").toURI().toURL());
 		assertEquals(4, c.size());
 		Iterator<Catalog> it = c.iterator();
 		it.next(); //discard the baseline
diff --git a/catalog/src/test/java/com/ning/billing/catalog/io/TestXMLReader.java b/catalog/src/test/java/com/ning/billing/catalog/io/TestXMLReader.java
new file mode 100644
index 0000000..c2add84
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/io/TestXMLReader.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog.io;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.xml.bind.JAXBException;
+import javax.xml.transform.TransformerException;
+
+import org.testng.annotations.Test;
+import org.xml.sax.SAXException;
+
+import com.ning.billing.catalog.api.InvalidConfigException;
+
+public class TestXMLReader {
+
+	@Test(enabled=true)
+	public void testCatalogLoad() throws IOException, TransformerException, JAXBException, SAXException, InvalidConfigException {
+		XMLReader.getCatalogFromName(new File("src/test/resources/WeaponsHire.xml").toURI().toURL());
+		XMLReader.getCatalogFromName(new File("src/test/resources/WeaponsHireSmall.xml").toURI().toURL());
+	}
+	
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java b/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
new file mode 100644
index 0000000..07a9b79
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.ProductCategory;
+
+public class MockCatalog extends Catalog {
+	private static final String[] PRODUCT_NAMES = new String[]{ "TestProduct1", "TestProduct2", "TestProduct3"};
+	
+	public MockCatalog() {
+		populateProducts();
+		populateRules();
+		populateProductTiers();
+		populatePlans();
+		populatePriceLists();
+	}
+	
+	public void populateRules(){
+		setPlanRules(new PlanRules());
+	}
+
+	public void setRules(PlanPolicyChangeRule[] rules,
+			CaseChangePlanPolicy[] caseChangePlanPolicy,
+			CaseChangePlanAlignment[] caseChangePlanAlignment,
+			CaseCancelPolicy[] caseCancelPolicy,
+			CaseCreateAlignment[] caseCreateAlignment
+			){
+		
+	}
+
+	public void populateProducts() {
+		String[] names = getProductNames();
+		Product[] products = new Product[names.length];
+		for(int i = 0; i < names.length; i++) {
+			products[i] = new Product(names[i], ProductCategory.BASE);
+		}
+		setProducts(products);
+	}
+
+	public void populateProductTiers() {
+		//default to having a single tier with all products in it
+		ProductTier tier = new ProductTier();
+		tier.setProducts(getProducts());
+		getPlanRules().setProductTiers(new ProductTier[]{tier});
+	}
+	
+	public void populatePlans() {
+		Product[] products = getProducts();
+		Plan[] plans = new Plan[products.length];
+		for(int i = 0; i < products.length; i++) {
+			plans[i] = new Plan(products[i].getName().toLowerCase() + "-plan",products[i],
+					new PlanPhase(BillingPeriod.MONTHLY, PhaseType.EVERGREEN));
+		}
+		setPlans(plans);
+	}
+
+	public void populatePriceLists() {
+		Plan[] plans = getPlans();
+		PriceList[] priceList = new PriceList[plans.length];
+		for(int i = 0; i < plans.length; i++) {
+			priceList[i] = new PriceList();
+			priceList[i].setName(plans[i].getName()+ "-pl");
+			priceList[i].setPlans(new Plan[]{plans[i]});
+		}
+		setPriceLists(priceList);
+	}
+	
+	public String[] getProductNames() {
+		return PRODUCT_NAMES;
+	}
+
+	
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/TestCase.java b/catalog/src/test/java/com/ning/billing/catalog/TestCase.java
new file mode 100644
index 0000000..5848c57
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/TestCase.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNull;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import org.testng.annotations.Test;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PlanSpecifier;
+import com.ning.billing.catalog.api.ProductCategory;
+
+public class TestCase {
+	protected enum Result {
+		FOO, BAR, WIBBLE
+	}
+	protected class CaseResult extends Case<Result>  {
+
+		@XmlElement(required=true)
+		private Result policy;
+
+		public CaseResult(Product product, ProductCategory productCategory, BillingPeriod billingPeriod, PriceList priceList,
+				 Result policy) {
+			super(product, productCategory, billingPeriod, priceList,  policy);
+			this.policy = policy;
+		}
+
+		@Override
+		protected Result getResult() {
+			return policy;
+		}
+	}
+
+	@Test(enabled=true)
+	public void testBasic(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product = cat.getProducts()[0];
+		PriceList priceList = cat.getPriceLists()[0];
+
+
+		CaseResult cr = new CaseResult(
+				product, 
+				ProductCategory.BASE,
+				BillingPeriod.MONTHLY, 
+				priceList,
+				Result.FOO);
+
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertionNull(cr, "lala", ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertionNull(cr, product.getName(), ProductCategory.ADD_ON,BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.ANNUAL, priceList.getName(), cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, "dipsy", cat);
+	}
+
+	@Test(enabled=true)
+	public void testWildCardProduct(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product = cat.getProducts()[0];
+		PriceList priceList = cat.getPriceLists()[0];
+
+
+		CaseResult cr = new CaseResult(
+				null, 
+				ProductCategory.BASE,
+				BillingPeriod.MONTHLY, 
+				priceList,
+
+				Result.FOO);
+
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertion(Result.FOO, cr,"lala", ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertionNull(cr, product.getName(), ProductCategory.ADD_ON,BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.ANNUAL, priceList.getName(), cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, "dipsy", cat);
+	}
+	
+	@Test(enabled=true)
+	public void testWildCardProductCategory(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product = cat.getProducts()[0];
+		PriceList priceList = cat.getPriceLists()[0];
+
+
+		CaseResult cr = new CaseResult(
+				product, 
+				null,
+				BillingPeriod.MONTHLY, 
+				priceList,
+
+				Result.FOO);
+
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertionNull(cr, "lala", ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.ADD_ON,BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.ANNUAL, priceList.getName(), cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, "dipsy", cat);
+	}
+	
+	@Test(enabled=true)
+	public void testWildCardBillingPeriod(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product = cat.getProducts()[0];
+		PriceList priceList = cat.getPriceLists()[0];
+
+
+		CaseResult cr = new CaseResult(
+				product, 
+				ProductCategory.BASE,
+				null, 
+				priceList,
+
+				Result.FOO);
+
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertionNull(cr, "lala", ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertionNull(cr, product.getName(), ProductCategory.ADD_ON,BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertion(Result.FOO,cr, product.getName(), ProductCategory.BASE,BillingPeriod.ANNUAL, priceList.getName(), cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, "dipsy", cat);
+	}
+
+	@Test(enabled=true)
+	public void testWildCardPriceList(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product = cat.getProducts()[0];
+		PriceList priceList = cat.getPriceLists()[0];
+
+
+		CaseResult cr = new CaseResult(
+				product, 
+				ProductCategory.BASE,
+				BillingPeriod.MONTHLY, 
+				null,
+
+				Result.FOO);
+
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertionNull(cr, "lala", ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertionNull(cr, product.getName(), ProductCategory.ADD_ON,BillingPeriod.MONTHLY, priceList.getName(), cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.ANNUAL, priceList.getName(), cat);
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, "dipsy", cat);
+	}
+
+	protected void assertionNull(CaseResult cr, String productName, ProductCategory productCategory, BillingPeriod bp, String priceListName, Catalog cat){
+		assertNull(cr.getResult(new PlanSpecifier(productName, productCategory, bp, priceListName), cat));
+	}
+
+	protected void assertion(Result result, CaseResult cr, String productName, ProductCategory productCategory, BillingPeriod bp, String priceListName,Catalog cat){
+		assertEquals(result, cr.getResult(new PlanSpecifier(productName, productCategory, bp, priceListName), cat));
+	}
+
+
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/TestCaseChange.java b/catalog/src/test/java/com/ning/billing/catalog/TestCaseChange.java
new file mode 100644
index 0000000..ed2972d
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/TestCaseChange.java
@@ -0,0 +1,977 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNull;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import org.testng.annotations.Test;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier; 
+import com.ning.billing.catalog.api.PlanSpecifier; 
+import com.ning.billing.catalog.api.ProductCategory;
+
+public class TestCaseChange {
+	protected enum Result {
+		FOO, BAR, WIBBLE
+	}
+	
+	protected class CaseChangeResult extends CaseChange<Result>  {
+
+		@XmlElement(required=true)
+		private Result result;
+
+		public CaseChangeResult(Product from, Product to, 
+				ProductCategory fromProductCategory, ProductCategory toProductCategory, 
+				BillingPeriod fromBP, BillingPeriod toBP, 
+				PriceList fromPriceList, PriceList toPriceList,
+				PhaseType fromType, 
+				Result result) {
+			super(from, to, 
+					fromProductCategory, toProductCategory,
+					fromBP, toBP, 
+					fromPriceList, toPriceList,
+					fromType, 
+					result);
+			this.result = result;
+		}
+
+		@Override
+		protected Result getResult() {
+			return result;
+		}
+	}
+	@Test(enabled=true)
+	public void testBasic(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product1 = cat.getProducts()[0];
+		PriceList priceList1 = cat.getPriceLists()[0];
+
+		Product product2 = cat.getProducts()[2];
+		PriceList priceList2 = cat.getPriceLists()[2];
+
+
+		CaseChangeResult cr = new CaseChangeResult(
+				product1, product2,
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1,priceList2,
+				PhaseType.EVERGREEN,
+				Result.FOO);
+
+		assertion(Result.FOO, cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				"wrong", product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), "wrong", 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.ADD_ON, ProductCategory.BASE,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.ADD_ON,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.ANNUAL, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.ANNUAL, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				"wrong", priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), "wrong", 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.TRIAL, cat);	
+	}
+	
+	@Test(enabled=true)
+	public void testWildcardFromProduct(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product1 = cat.getProducts()[0];
+		PriceList priceList1 = cat.getPriceLists()[0];
+
+		Product product2 = cat.getProducts()[2];
+		PriceList priceList2 = cat.getPriceLists()[2];
+
+
+		CaseChangeResult cr = new CaseChangeResult(
+				null, product2,
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1,priceList2,
+				PhaseType.EVERGREEN,
+				Result.FOO);
+
+		assertion(Result.FOO, cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertion(Result.FOO,cr, 
+				"wrong", product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+			
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.ADD_ON, ProductCategory.BASE,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.ADD_ON,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+
+		assertionNull(cr, 
+				product1.getName(), "wrong", 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.ANNUAL, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.ANNUAL, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				"wrong", priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), "wrong", 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.TRIAL, cat);	
+	}
+	
+	@Test(enabled=true)
+	public void testWildcardToProduct(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product1 = cat.getProducts()[0];
+		PriceList priceList1 = cat.getPriceLists()[0];
+
+		Product product2 = cat.getProducts()[2];
+		PriceList priceList2 = cat.getPriceLists()[2];
+
+
+		CaseChangeResult cr = new CaseChangeResult(
+				product1, null,
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1,priceList2,
+				PhaseType.EVERGREEN,
+				Result.FOO);
+
+		assertion(Result.FOO, cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				"wrong", product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.ADD_ON, ProductCategory.BASE,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.ADD_ON,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertion(Result.FOO, cr, 
+				product1.getName(), "wrong", 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.ANNUAL, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.ANNUAL, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				"wrong", priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), "wrong", 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.TRIAL, cat);	
+	}
+	
+	@Test(enabled=true)
+	public void testWildcardFromProductCategory(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product1 = cat.getProducts()[0];
+		PriceList priceList1 = cat.getPriceLists()[0];
+
+		Product product2 = cat.getProducts()[2];
+		PriceList priceList2 = cat.getPriceLists()[2];
+
+
+		CaseChangeResult cr = new CaseChangeResult(
+				product1, product2,
+				null, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1,priceList2,
+				PhaseType.EVERGREEN,
+				Result.FOO);
+
+		assertion(Result.FOO, cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				"wrong", product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), "wrong", 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertion(Result.FOO, cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.ADD_ON, ProductCategory.BASE,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.ADD_ON,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.ANNUAL, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.ANNUAL, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				"wrong", priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), "wrong", 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.TRIAL, cat);	
+	}
+	
+	@Test(enabled=true)
+	public void testWildcardToProductCategory(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product1 = cat.getProducts()[0];
+		PriceList priceList1 = cat.getPriceLists()[0];
+
+		Product product2 = cat.getProducts()[2];
+		PriceList priceList2 = cat.getPriceLists()[2];
+
+
+		CaseChangeResult cr = new CaseChangeResult(
+				product1, product2,
+				ProductCategory.BASE, null,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1,priceList2,
+				PhaseType.EVERGREEN,
+				Result.FOO);
+
+		assertion(Result.FOO, cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				"wrong", product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), "wrong", 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.ADD_ON, ProductCategory.BASE,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertion(Result.FOO, cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.ADD_ON,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.ANNUAL, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.ANNUAL, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				"wrong", priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), "wrong", 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.TRIAL, cat);	
+	}
+	
+	@Test(enabled=true)
+	public void testWildcardFromBillingPeriod(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product1 = cat.getProducts()[0];
+		PriceList priceList1 = cat.getPriceLists()[0];
+
+		Product product2 = cat.getProducts()[2];
+		PriceList priceList2 = cat.getPriceLists()[2];
+
+
+		CaseChangeResult cr = new CaseChangeResult(
+				product1, product2,
+				ProductCategory.BASE, ProductCategory.BASE,
+				null, BillingPeriod.MONTHLY, 
+				priceList1, priceList2,
+				PhaseType.EVERGREEN,
+				Result.FOO);
+
+		assertion(Result.FOO, cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				"wrong", product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.ADD_ON, ProductCategory.BASE,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.ADD_ON,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), "wrong", 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertion(Result.FOO,cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.ANNUAL, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.ANNUAL, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				"wrong", priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), "wrong", 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.TRIAL, cat);	
+	}
+	
+	
+	@Test(enabled=true)
+	public void testWildCardToBillingPeriod(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product1 = cat.getProducts()[0];
+		PriceList priceList1 = cat.getPriceLists()[0];
+
+		Product product2 = cat.getProducts()[2];
+		PriceList priceList2 = cat.getPriceLists()[2];
+
+
+		CaseChangeResult cr = new CaseChangeResult(
+				product1, product2,
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, null, 
+				priceList1,priceList2,
+				PhaseType.EVERGREEN,
+				Result.FOO);
+
+		assertion(Result.FOO, cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				"wrong", product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.ADD_ON, ProductCategory.BASE,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.ADD_ON,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), "wrong", 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.ANNUAL, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertion(Result.FOO,cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.ANNUAL, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				"wrong", priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), "wrong", 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.TRIAL, cat);	
+	}
+	
+	@Test(enabled=true)
+	public void testWildCardFromPriceList(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product1 = cat.getProducts()[0];
+		PriceList priceList1 = cat.getPriceLists()[0];
+
+		Product product2 = cat.getProducts()[2];
+		PriceList priceList2 = cat.getPriceLists()[2];
+
+
+		CaseChangeResult cr = new CaseChangeResult(
+				product1, product2,
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				null,priceList2,
+				PhaseType.EVERGREEN,
+				Result.FOO);
+
+		assertion(Result.FOO, cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				"wrong", product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.ADD_ON, ProductCategory.BASE,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.ADD_ON,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), "wrong", 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.ANNUAL, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.ANNUAL, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertion(Result.FOO,cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				"wrong", priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), "wrong", 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.TRIAL, cat);	
+	}
+	
+	@Test(enabled=true)
+	public void testWildcardToPriceList(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product1 = cat.getProducts()[0];
+		PriceList priceList1 = cat.getPriceLists()[0];
+
+		Product product2 = cat.getProducts()[2];
+		PriceList priceList2 = cat.getPriceLists()[2];
+
+
+		CaseChangeResult cr = new CaseChangeResult(
+				product1, product2,
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1,null,
+				PhaseType.EVERGREEN,
+				Result.FOO);
+
+		assertion(Result.FOO, cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				"wrong", product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.ADD_ON, ProductCategory.BASE,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.ADD_ON,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), "wrong", 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.ANNUAL, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.ANNUAL, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				"wrong", priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertion(Result.FOO,cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), "wrong", 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.TRIAL, cat);	
+	}
+	
+	@Test(enabled=true)
+	public void testWildcardPlanPhase(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product1 = cat.getProducts()[0];
+		PriceList priceList1 = cat.getPriceLists()[0];
+
+		Product product2 = cat.getProducts()[2];
+		PriceList priceList2 = cat.getPriceLists()[2];
+
+
+		CaseChangeResult cr = new CaseChangeResult(
+				product1, product2,
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1,priceList2,
+				null,
+				Result.FOO);
+
+		assertion(Result.FOO, cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				"wrong", product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.ADD_ON, ProductCategory.BASE,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull( cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.ADD_ON,				
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), "wrong", 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.ANNUAL, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.ANNUAL, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				"wrong", priceList2.getName(), 
+				PhaseType.EVERGREEN, cat);
+		
+		assertionNull(cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), "wrong", 
+				PhaseType.EVERGREEN, cat);
+		
+		assertion(Result.FOO,cr, 
+				product1.getName(), product2.getName(), 
+				ProductCategory.BASE, ProductCategory.BASE,
+				BillingPeriod.MONTHLY, BillingPeriod.MONTHLY, 
+				priceList1.getName(), priceList2.getName(), 
+				PhaseType.TRIAL, cat);	
+	}
+	
+	
+	protected void assertionNull(CaseChangeResult cr, 
+			String fromProductName, String toProductName,
+			ProductCategory fromProductCategory, ProductCategory toProductCategory, 
+			BillingPeriod fromBp, BillingPeriod toBp,
+			String fromPriceListName, String toPriceListName,
+			PhaseType phaseType, Catalog cat){
+		assertNull(cr.getResult(new PlanPhaseSpecifier(fromProductName, fromProductCategory, fromBp, fromPriceListName, phaseType), 
+								new PlanSpecifier(toProductName, toProductCategory, toBp, toPriceListName),cat));
+	}
+
+	protected void assertion(Result result, CaseChangeResult cr, 
+			String fromProductName, String toProductName,
+			ProductCategory fromProductCategory, ProductCategory toProductCategory, 
+			BillingPeriod fromBp, BillingPeriod toBp,
+			String fromPriceListName, String toPriceListName,
+			PhaseType phaseType, Catalog cat){
+		assertEquals(result, cr.getResult(new PlanPhaseSpecifier(fromProductName, fromProductCategory,fromBp, fromPriceListName, phaseType), 
+								new PlanSpecifier(toProductName, toProductCategory, toBp, toPriceListName),cat));
+	}
+
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/TestCasePhase.java b/catalog/src/test/java/com/ning/billing/catalog/TestCasePhase.java
new file mode 100644
index 0000000..9d3f7cc
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/TestCasePhase.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.catalog;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNull;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import org.testng.annotations.Test;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.ProductCategory;
+
+public class TestCasePhase {
+	protected enum Result {
+		FOO, BAR, WIBBLE
+	}
+	protected class CaseResult extends CasePhase<Result>  {
+
+		@XmlElement(required=true)
+		private Result policy;
+
+		public CaseResult(Product product, ProductCategory productCategory, BillingPeriod billingPeriod, PriceList priceList,
+				PhaseType phaseType, Result policy) {
+			super(product, productCategory, billingPeriod, priceList, phaseType, policy);
+			this.policy = policy;
+		}
+
+		@Override
+		protected Result getResult() {
+			return policy;
+		}
+	}
+
+	@Test(enabled=true)
+	public void testBasic(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product = cat.getProducts()[0];
+		PriceList priceList = cat.getPriceLists()[0];
+
+
+		CaseResult cr = new CaseResult(
+				product, 
+				ProductCategory.BASE,
+				BillingPeriod.MONTHLY, 
+				priceList,
+				PhaseType.EVERGREEN, 
+				Result.FOO);
+
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, "lala", ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.ADD_ON,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, "dipsy", PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.TRIAL, cat);
+	}
+
+	@Test(enabled=true)
+	public void testWildCardProduct(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product = cat.getProducts()[0];
+		PriceList priceList = cat.getPriceLists()[0];
+
+
+		CaseResult cr = new CaseResult(
+				null, 
+				ProductCategory.BASE,
+				BillingPeriod.MONTHLY, 
+				priceList,
+				PhaseType.EVERGREEN, 
+				Result.FOO);
+
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertion(Result.FOO, cr,"lala", ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.ADD_ON,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, "dipsy", PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.TRIAL, cat);
+	}
+	
+	@Test(enabled=true)
+	public void testWildCardProductCategory(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product = cat.getProducts()[0];
+		PriceList priceList = cat.getPriceLists()[0];
+
+
+		CaseResult cr = new CaseResult(
+				product, 
+				null,
+				BillingPeriod.MONTHLY, 
+				priceList,
+				PhaseType.EVERGREEN, 
+				Result.FOO);
+
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, "lala", ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.ADD_ON,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, "dipsy", PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.TRIAL, cat);
+	}
+	
+	@Test(enabled=true)
+	public void testWildCardBillingPeriod(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product = cat.getProducts()[0];
+		PriceList priceList = cat.getPriceLists()[0];
+
+
+		CaseResult cr = new CaseResult(
+				product, 
+				ProductCategory.BASE,
+				null, 
+				priceList,
+				PhaseType.EVERGREEN, 
+				Result.FOO);
+
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, "lala", ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.ADD_ON,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertion(Result.FOO,cr, product.getName(), ProductCategory.BASE,BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, "dipsy", PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.TRIAL, cat);
+	}
+
+	@Test(enabled=true)
+	public void testWildCardPriceList(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product = cat.getProducts()[0];
+		PriceList priceList = cat.getPriceLists()[0];
+
+
+		CaseResult cr = new CaseResult(
+				product, 
+				ProductCategory.BASE,
+				BillingPeriod.MONTHLY, 
+				null,
+				PhaseType.EVERGREEN, 
+				Result.FOO);
+
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, "lala", ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.ADD_ON,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, "dipsy", PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.TRIAL, cat);
+	}
+
+	@Test(enabled=true)
+	public void testWildCardPhaseType(){
+		MockCatalog cat = new MockCatalog();
+
+		Product product = cat.getProducts()[0];
+		PriceList priceList = cat.getPriceLists()[0];
+
+
+		CaseResult cr = new CaseResult(
+				product, 
+				ProductCategory.BASE,
+				BillingPeriod.MONTHLY, 
+				priceList,
+				null, 
+				Result.FOO);
+
+		assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, "lala", ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.ADD_ON,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE,BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN, cat);
+		assertionNull(cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, "dipsy", PhaseType.EVERGREEN, cat);
+		assertion(Result.FOO,cr, product.getName(), ProductCategory.BASE,BillingPeriod.MONTHLY, priceList.getName(), PhaseType.TRIAL, cat);
+	}
+
+	protected void assertionNull(CaseResult cr, String productName, ProductCategory productCategory, BillingPeriod bp, String priceListName, PhaseType phaseType, Catalog cat){
+		assertNull(cr.getResult(new PlanPhaseSpecifier(productName, productCategory, bp, priceListName, phaseType), cat));
+	}
+
+	protected void assertion(Result result, CaseResult cr, String productName, ProductCategory productCategory, BillingPeriod bp, String priceListName, PhaseType phaseType, Catalog cat){
+		assertEquals(result, cr.getResult(new PlanPhaseSpecifier(productName, productCategory, bp, priceListName, phaseType), cat));
+	}
+
+
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/TestPlanChangeRules.java b/catalog/src/test/java/com/ning/billing/catalog/TestPlanChangeRules.java
index ef0fe65..2ea4319 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/TestPlanChangeRules.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/TestPlanChangeRules.java
@@ -27,7 +27,7 @@ import static org.testng.AssertJUnit.assertNull;
 
 import org.testng.annotations.Test;
 
-import com.ning.billing.catalog.PlanChangeRule.Qualifier;
+import com.ning.billing.catalog.PlanPolicyChangeRule.Qualifier;
 import com.ning.billing.catalog.api.ActionPolicy;
 import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
@@ -40,8 +40,8 @@ public class TestPlanChangeRules extends TestPlanRules {
 		Product P2 = createProduct("BP");
 
 		Catalog c = createCatalog(
-				new PlanChangeRule[]{
-						new PlanChangeRule(Qualifier.DEFAULT, ActionPolicy.END_OF_TERM, null)
+				new PlanPolicyChangeRule[]{
+						new PlanPolicyChangeRule(Qualifier.DEFAULT, ActionPolicy.END_OF_TERM, null)
 				}, 
 				null,
 				null,
@@ -49,8 +49,8 @@ public class TestPlanChangeRules extends TestPlanRules {
 				P2
 				);
 		assertEquals(ActionPolicy.END_OF_TERM,c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("FP", ANNUAL, null, EVERGREEN),
-				new PlanPhaseSpecifier("BP", ANNUAL, null, EVERGREEN)
+				new PlanPhaseSpecifier("FP", null, ANNUAL, null, EVERGREEN),
+				new PlanPhaseSpecifier("BP", null, ANNUAL, null, EVERGREEN)
 				));
 	}
 
@@ -60,8 +60,8 @@ public class TestPlanChangeRules extends TestPlanRules {
 		Product P2 = createProduct("BP");
 
 		Catalog c = createCatalog(
-				new PlanChangeRule[]{
-						new PlanChangeRule(Qualifier.TERM_FROM_LONG_TO_SHORT, END_OF_TERM, null)
+				new PlanPolicyChangeRule[]{
+						new PlanPolicyChangeRule(Qualifier.TERM_FROM_LONG_TO_SHORT, END_OF_TERM, null)
 				}, 
 				null,
 				null,
@@ -70,13 +70,13 @@ public class TestPlanChangeRules extends TestPlanRules {
 				);
 		
 		assertEquals(END_OF_TERM,c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("FP", ANNUAL, null, EVERGREEN),
-				new PlanPhaseSpecifier("BP", MONTHLY, null, EVERGREEN)
+				new PlanPhaseSpecifier("FP", null, ANNUAL, null, EVERGREEN),
+				new PlanPhaseSpecifier("BP", null, MONTHLY, null, EVERGREEN)
 				));
 		
 		assertNull(c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("FP", MONTHLY, null, EVERGREEN),
-				new PlanPhaseSpecifier("BP", ANNUAL, null, EVERGREEN)
+				new PlanPhaseSpecifier("FP", null, MONTHLY, null, EVERGREEN),
+				new PlanPhaseSpecifier("BP", null, ANNUAL, null, EVERGREEN)
 				));
 
 
@@ -89,8 +89,8 @@ public class TestPlanChangeRules extends TestPlanRules {
 		Product P2 = createProduct("BP");
 
 		Catalog c = createCatalog(
-				new PlanChangeRule[]{
-						new PlanChangeRule(Qualifier.TERM_FROM_SHORT_TO_LONG, END_OF_TERM, null)
+				new PlanPolicyChangeRule[]{
+						new PlanPolicyChangeRule(Qualifier.TERM_FROM_SHORT_TO_LONG, END_OF_TERM, null)
 				}, 
 				null,
 				null,
@@ -99,13 +99,13 @@ public class TestPlanChangeRules extends TestPlanRules {
 				);
 
 		assertEquals(END_OF_TERM,c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("FP", MONTHLY, null, EVERGREEN),
-				new PlanPhaseSpecifier("BP", ANNUAL, null, EVERGREEN)
+				new PlanPhaseSpecifier("FP", null, MONTHLY, null, EVERGREEN),
+				new PlanPhaseSpecifier("BP", null, ANNUAL, null, EVERGREEN)
 				));
 		
 		assertNull(c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("FP", ANNUAL, null, EVERGREEN),
-				new PlanPhaseSpecifier("BP", MONTHLY, null, EVERGREEN)
+				new PlanPhaseSpecifier("FP", null, ANNUAL, null, EVERGREEN),
+				new PlanPhaseSpecifier("BP", null, MONTHLY, null, EVERGREEN)
 				));
 
 }
@@ -116,8 +116,8 @@ public class TestPlanChangeRules extends TestPlanRules {
 		Product P2 = createProduct("BP");
 
 		Catalog c = createCatalog(
-				new PlanChangeRule[]{
-						new PlanChangeRule(Qualifier.TERM_FROM_SHORT_TO_LONG, END_OF_TERM, PhaseType.EVERGREEN)
+				new PlanPolicyChangeRule[]{
+						new PlanPolicyChangeRule(Qualifier.TERM_FROM_SHORT_TO_LONG, END_OF_TERM, PhaseType.EVERGREEN)
 				}, 
 				null,
 				null,
@@ -126,13 +126,13 @@ public class TestPlanChangeRules extends TestPlanRules {
 				);
 
 		assertEquals(END_OF_TERM,c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("FP", MONTHLY, null, EVERGREEN),
-				new PlanPhaseSpecifier("BP", ANNUAL, null, EVERGREEN)
+				new PlanPhaseSpecifier("FP", null, MONTHLY, null, EVERGREEN),
+				new PlanPhaseSpecifier("BP", null, ANNUAL, null, EVERGREEN)
 				));
 		
 		assertNull(c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("FP", MONTHLY, null, TRIAL),
-				new PlanPhaseSpecifier("BP", ANNUAL, null, TRIAL)
+				new PlanPhaseSpecifier("FP", null, MONTHLY, null, TRIAL),
+				new PlanPhaseSpecifier("BP", null, ANNUAL, null, TRIAL)
 				));
 		
 	}
@@ -143,8 +143,8 @@ public class TestPlanChangeRules extends TestPlanRules {
 		Product P2 = createProduct("BP");
 
 		Catalog c = createCatalog(
-				new PlanChangeRule[]{
-						new PlanChangeRule(Qualifier.PRODUCT_FROM_LOW_TO_HIGH, IMMEDIATE, null)
+				new PlanPolicyChangeRule[]{
+						new PlanPolicyChangeRule(Qualifier.PRODUCT_FROM_LOW_TO_HIGH, IMMEDIATE, null)
 				}, 
 				null,
 				null,
@@ -153,13 +153,13 @@ public class TestPlanChangeRules extends TestPlanRules {
 				);
 		
 		assertEquals(IMMEDIATE,c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("FP", MONTHLY, null, EVERGREEN),
-				new PlanPhaseSpecifier("BP", ANNUAL, null, EVERGREEN)
+				new PlanPhaseSpecifier("FP", null, MONTHLY, null, EVERGREEN),
+				new PlanPhaseSpecifier("BP", null, ANNUAL, null, EVERGREEN)
 				));
 		
 		assertNull(c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("BP", MONTHLY, null, EVERGREEN),
-				new PlanPhaseSpecifier("FP", ANNUAL, null, EVERGREEN)
+				new PlanPhaseSpecifier("BP", null, MONTHLY, null, EVERGREEN),
+				new PlanPhaseSpecifier("FP", null, ANNUAL, null, EVERGREEN)
 				));
 		
 
@@ -171,8 +171,8 @@ public class TestPlanChangeRules extends TestPlanRules {
 		Product P2 = createProduct("BP");
 
 		Catalog c = createCatalog(
-				new PlanChangeRule[]{
-						new PlanChangeRule(Qualifier.PRODUCT_FROM_HIGH_TO_LOW, IMMEDIATE, null)
+				new PlanPolicyChangeRule[]{
+						new PlanPolicyChangeRule(Qualifier.PRODUCT_FROM_HIGH_TO_LOW, IMMEDIATE, null)
 				}, 
 				null,
 				null,
@@ -181,13 +181,13 @@ public class TestPlanChangeRules extends TestPlanRules {
 				);
 
 		assertEquals(IMMEDIATE,c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("BP", ANNUAL, null, EVERGREEN),
-				new PlanPhaseSpecifier("FP", MONTHLY, null, EVERGREEN)
+				new PlanPhaseSpecifier("BP", null, ANNUAL, null, EVERGREEN),
+				new PlanPhaseSpecifier("FP", null, MONTHLY, null, EVERGREEN)
 				));
 		
 		assertNull(c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("FP", MONTHLY, null, TRIAL),
-				new PlanPhaseSpecifier("BP", ANNUAL, null, TRIAL)
+				new PlanPhaseSpecifier("FP", null, MONTHLY, null, TRIAL),
+				new PlanPhaseSpecifier("BP", null, ANNUAL, null, TRIAL)
 				));
 		
 	}
@@ -198,12 +198,12 @@ public class TestPlanChangeRules extends TestPlanRules {
 		Product P2 = createProduct("BP");
 
 		Catalog c = createCatalog(
-				new PlanChangeRule[]{
-						new PlanChangeRule(Qualifier.TERM_FROM_LONG_TO_SHORT, IMMEDIATE, null),
-						new PlanChangeRule(Qualifier.PRODUCT_FROM_LOW_TO_HIGH, END_OF_TERM, null)
+				new PlanPolicyChangeRule[]{
+						new PlanPolicyChangeRule(Qualifier.TERM_FROM_LONG_TO_SHORT, IMMEDIATE, null),
+						new PlanPolicyChangeRule(Qualifier.PRODUCT_FROM_LOW_TO_HIGH, END_OF_TERM, null)
 				}, 
-				new PlanChangeCase[] {
-						new PlanChangeCase(P1, P2, MONTHLY, MONTHLY, null, null, null, null, null  ), 
+				new CaseChangePlanPolicy[] {
+						new CaseChangePlanPolicy(P1, P2, null, null, MONTHLY, MONTHLY, null, null, null, IMMEDIATE  ), 
 				},
 				null,
 				P1,
@@ -211,16 +211,42 @@ public class TestPlanChangeRules extends TestPlanRules {
 				);
 		
 		assertEquals(END_OF_TERM,c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("FP", ANNUAL, null, EVERGREEN),
-				new PlanPhaseSpecifier("BP", MONTHLY, null, EVERGREEN)
+				new PlanPhaseSpecifier("FP", null, ANNUAL, null, EVERGREEN),
+				new PlanPhaseSpecifier("BP", null, MONTHLY, null, EVERGREEN)
 				));
 		
 		assertNull(c.getPlanChangePolicy(
-				new PlanPhaseSpecifier("BP", MONTHLY, null, EVERGREEN),
-				new PlanPhaseSpecifier("FP", ANNUAL, null, EVERGREEN)
+				new PlanPhaseSpecifier("BP", null, MONTHLY, null, EVERGREEN),
+				new PlanPhaseSpecifier("FP", null, ANNUAL, null, EVERGREEN)
 				));
 
 	}
+	@Test(enabled=true)
+	public void testPrecedenceSpecialCaseTrumpsRule() {
+		Product P1 = createProduct("FP");
+		Product P2 = createProduct("BP");
 
+		Catalog c = createCatalog(
+				new PlanPolicyChangeRule[]{
+						new PlanPolicyChangeRule(Qualifier.PRODUCT_FROM_LOW_TO_HIGH, END_OF_TERM, null)
+				}, 
+				new CaseChangePlanPolicy[] {
+						new CaseChangePlanPolicy(P1, P2, null, null, ANNUAL, MONTHLY, null, null, null, IMMEDIATE ), 
+				},
+				null,
+				P1,
+				P2
+				);
+		
+		assertEquals(IMMEDIATE,c.getPlanChangePolicy(
+				new PlanPhaseSpecifier("FP", null, ANNUAL, null, EVERGREEN),
+				new PlanPhaseSpecifier("BP", null, MONTHLY, null, EVERGREEN)
+				));
+		
+		assertNull(c.getPlanChangePolicy(
+				new PlanPhaseSpecifier("BP", null, MONTHLY, null, EVERGREEN),
+				new PlanPhaseSpecifier("FP", null, ANNUAL, null, EVERGREEN)
+				));
 
+	}
 }
diff --git a/catalog/src/test/java/com/ning/billing/catalog/TestPlanRules.java b/catalog/src/test/java/com/ning/billing/catalog/TestPlanRules.java
index 0f2ff50..6121a85 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/TestPlanRules.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/TestPlanRules.java
@@ -15,47 +15,54 @@
  */
 package com.ning.billing.catalog;
 
+import com.ning.billing.catalog.api.ProductCategory;
+
 
 public class TestPlanRules {
 
-	public Catalog createCatalog(PlanChangeRule[] generalRules, 
-			PlanChangeCase[] specialCaseRules,
-			PlanCancelCase[] cancelCaseRules,
+	public Catalog createCatalog(PlanPolicyChangeRule[] generalRules, 
+			CaseChangePlanPolicy[] specialCaseRules,
+			CaseCancelPolicy[] cancelCaseRules,
 					Product fromP,
 					Product toP) {
 		Catalog c = new Catalog();
-		PlanRules pcr = new PlanRules();
-		pcr.setGeneralRules(generalRules);
-		pcr.setSpecialCaseRules(specialCaseRules);
-		pcr.setCancelCaseRules(cancelCaseRules);
+		PlanRules pcr = new PlanRules(
+				new ProductTier[] {new ProductTier(new Product[]{ fromP, toP })},
+				generalRules,
+				specialCaseRules,
+				cancelCaseRules,
+				null,
+				null
+		);
 		c.setPlanChangeRules(pcr);
-		pcr.setProductTiers(new ProductTier[] {new ProductTier(new Product[]{ fromP, toP })});
 		c.setProducts(new Product[] { fromP, toP });
 		return c;
 	}
 	
-	public Catalog createCatalog(PlanChangeRule[] generalRules, 
-			PlanChangeCase[] specialCaseRules,
-			PlanCancelCase[] cancelCaseRules,
-			PlanAlignmentCase[] alignmentCases,
+	public Catalog createCatalog(PlanPolicyChangeRule[] generalRules, 
+			CaseChangePlanPolicy[] specialCaseRules,
+			CaseCancelPolicy[] cancelCaseRules,
+			CaseChangePlanAlignment[] alignmentChangeCases,
 					Product fromP,
 					Product toP) {
 		Catalog c = new Catalog();
-		PlanRules pcr = new PlanRules();
-		pcr.setGeneralRules(generalRules);
-		pcr.setSpecialCaseRules(specialCaseRules);
-		pcr.setCancelCaseRules(cancelCaseRules);
-		pcr.setAlignmentCase(alignmentCases);
+		PlanRules pcr = new PlanRules(
+				new ProductTier[] {new ProductTier(new Product[]{ fromP, toP })},
+				generalRules,
+				specialCaseRules,
+				cancelCaseRules,
+				alignmentChangeCases,
+				null
+		);
+
 		c.setPlanChangeRules(pcr);
-		pcr.setProductTiers(new ProductTier[] {new ProductTier(new Product[]{ fromP, toP })});
 		c.setProducts(new Product[] { fromP, toP });
 		return c;
 	}
 
 	
 	public Product createProduct(String name) {
-		ProductType type = new ProductType("TestType");
-		return new Product(type, name);
+		return new Product(name, ProductCategory.BASE);
 	}
 	
 
diff --git a/catalog/src/test/java/com/ning/billing/catalog/TestVersionedCatalog.java b/catalog/src/test/java/com/ning/billing/catalog/TestVersionedCatalog.java
index a4d211c..a9a9cca 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/TestVersionedCatalog.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/TestVersionedCatalog.java
@@ -30,36 +30,39 @@ import org.xml.sax.SAXException;
 import com.ning.billing.catalog.Catalog;
 import com.ning.billing.catalog.VersionedCatalog;
 import com.ning.billing.catalog.api.InvalidConfigException;
+import com.ning.billing.catalog.io.ICatalogLoader;
 import com.ning.billing.catalog.io.VersionedCatalogLoader;
 
 public class TestVersionedCatalog {
+	private final ICatalogLoader loader = new VersionedCatalogLoader();
+
 	@Test(enabled=true)
 	public void testAddCatalog() throws MalformedURLException, IOException, SAXException, InvalidConfigException, JAXBException {
-		VersionedCatalog vc = VersionedCatalogLoader.load(new File("src/test/resources/versionedCatalog").toURI().toURL());
+		VersionedCatalog vc = loader.load(new File("src/test/resources/versionedCatalog").toURI().toURL());
 		vc.add(new Catalog(new Date()));
 		assertEquals(5, vc.size());
 	}
 	
 	@Test(enabled=true)
 	public void testApplyEffectiveDate() throws MalformedURLException, IOException, SAXException, InvalidConfigException, JAXBException {
-		VersionedCatalog vc = VersionedCatalogLoader.load(new File("src/test/resources/versionedCatalog").toURI().toURL());
+		VersionedCatalog vc = loader.load(new File("src/test/resources/versionedCatalog").toURI().toURL());
 		Date d = new Date(1L);
-		vc.applyEffectiveDate(d);
+		vc.configureEffectiveDate(d);
 		assertEquals(new Date(0), vc.getEffectiveDate()); // Start at the begining of time
 		
 		DateTime dt = new DateTime("2011-01-01T00:00:00+00:00");
 		d = new Date(dt.getMillis() + 1000);
-		vc.applyEffectiveDate(d);
+		vc.configureEffectiveDate(d);
 		assertEquals(dt.toDate(),vc.getEffectiveDate());
 		
 		dt = new DateTime("2011-02-02T00:00:00+00:00");
 		d = new Date(dt.getMillis() + 1000);
-		vc.applyEffectiveDate(d);
+		vc.configureEffectiveDate(d);
 		assertEquals(dt.toDate(),vc.getEffectiveDate());
 		
 		dt = new DateTime("2011-03-03T00:00:00+00:00");
 		d = new Date(dt.getMillis() + 1000);
-		vc.applyEffectiveDate(d);
+		vc.configureEffectiveDate(d);
 		assertEquals(dt.toDate(),vc.getEffectiveDate());
 		
 	}
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
index ead1bb0..51e68dc 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
@@ -19,28 +19,22 @@
 	xsi:noNamespaceSchemaLocation="../../../main/resources/CatalogSchema.xsd ">
 
 	<effectiveDate>2011-01-01T00:00:00+00:00</effectiveDate>
+	<catalogName>WeaponsHireSmall</catalogName>
 
 	<currencies>
 		<currency>USD</currency>
 		<currency>EUR</currency>
 		<currency>GBP</currency>
 	</currencies>
-	
-	<productTypes>
-		<productType name="Firearms" />
-	</productTypes>
 
 	<products>
 		<product name="Pistol">
-			<type>Firearms</type>
 			<category>BASE</category>
 		</product>
 		<product name="Shotgun">
-			<type>Firearms</type>
 			<category>BASE</category>
 		</product>
 		<product name="Laser-Scope">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 	</products>
@@ -52,35 +46,35 @@
 				<product>Shotgun</product>
 			</tier>
 		</tiers>
-		<changeRule>
+		<changePolicyRule>
 			<qualifier>DEFAULT</qualifier>
 			<policy>END_OF_TERM</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>TERM_FROM_SHORT_TO_LONG</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>PRODUCT_FROM_LOW_TO_HIGH</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>PRODUCT_FROM_LOW_TO_HIGH</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeCase> 
+		</changePolicyRule>
+		<changePolicyCase> 
 			<fromBillingPeriod>MONTHLY</fromBillingPeriod>
 			<toProduct>Shotgun</toProduct>
 			<toBillingPeriod>MONTHLY</toBillingPeriod>
 			<policy>END_OF_TERM</policy>
-		</changeCase>
-		<changeCase> 
+		</changePolicyCase>
+		<changePolicyCase> 
 			<phaseType>TRIAL</phaseType>
 			<policy>IMMEDIATE</policy>
-		</changeCase>	
-		<alignmentCase>
+		</changePolicyCase>	
+		<changeAlignmentCase>
 			<alignment>START_OF_SUBSCRIPTION</alignment>
-		</alignmentCase>
+		</changeAlignmentCase>
 	</rules>
 
 	<plans>
@@ -107,7 +101,6 @@
 					<price><currency>USD</currency><value>29.95</value></price>								
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="shotgun-monthly">
 			<product>Shotgun</product>
@@ -133,7 +126,6 @@
 					<price><currency>GBP</currency><value>169.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="shotgun-annual">
 			<product>Shotgun</product>
@@ -158,7 +150,6 @@
 					<price><currency>GBP</currency><value>1699.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 	</plans>
 	<priceLists>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
index 8d32846..3ad25f3 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
@@ -19,28 +19,22 @@
 	xsi:noNamespaceSchemaLocation="../../../main/resources/CatalogSchema.xsd ">
 
 	<effectiveDate>2011-02-02T00:00:00+00:00</effectiveDate>
+	<catalogName>WeaponsHireSmall</catalogName>
 
 	<currencies>
 		<currency>USD</currency>
 		<currency>EUR</currency>
 		<currency>GBP</currency>
 	</currencies>
-	
-	<productTypes>
-		<productType name="Firearms" />
-	</productTypes>
 
 	<products>
 		<product name="Pistol">
-			<type>Firearms</type>
 			<category>BASE</category>
 		</product>
 		<product name="Shotgun">
-			<type>Firearms</type>
 			<category>BASE</category>
 		</product>
 		<product name="Laser-Scope">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 	</products>
@@ -52,38 +46,37 @@
 				<product>Shotgun</product>
 			</tier>
 		</tiers>
-		<changeRule>
+		<changePolicyRule>
 			<qualifier>DEFAULT</qualifier>
 			<policy>END_OF_TERM</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>TERM_FROM_SHORT_TO_LONG</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>PRODUCT_FROM_LOW_TO_HIGH</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>PRODUCT_FROM_LOW_TO_HIGH</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeCase> 
+		</changePolicyRule>
+		<changePolicyCase> 
 			<fromBillingPeriod>MONTHLY</fromBillingPeriod>
 			<toProduct>Shotgun</toProduct>
 			<toBillingPeriod>MONTHLY</toBillingPeriod>
 			<policy>END_OF_TERM</policy>
-		</changeCase>
-		<changeCase> 
+		</changePolicyCase>
+		<changePolicyCase> 
 			<phaseType>TRIAL</phaseType>
 			<policy>IMMEDIATE</policy>
-		</changeCase>
-		<alignmentCase>
+		</changePolicyCase>	
+		<changeAlignmentCase>
 			<alignment>START_OF_SUBSCRIPTION</alignment>
-		</alignmentCase>			
+		</changeAlignmentCase>
 	</rules>
 
-
 	<plans>
 		<plan name="pistol-monthly">
 			<product>Pistol</product>
@@ -108,7 +101,6 @@
 					<price><currency>USD</currency><value>29.95</value></price>								
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="shotgun-monthly">
 			<product>Shotgun</product>
@@ -134,7 +126,6 @@
 					<price><currency>GBP</currency><value>169.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="shotgun-annual">
 			<product>Shotgun</product>
@@ -159,7 +150,6 @@
 					<price><currency>GBP</currency><value>1699.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 	</plans>
 	<priceLists>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
index e1c8bff..20ca041 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
@@ -19,28 +19,22 @@
 	xsi:noNamespaceSchemaLocation="../../../main/resources/CatalogSchema.xsd ">
 
 	<effectiveDate>2011-03-03T00:00:00+00:00</effectiveDate>
+	<catalogName>WeaponsHireSmall</catalogName>
 
 	<currencies>
 		<currency>USD</currency>
 		<currency>EUR</currency>
 		<currency>GBP</currency>
 	</currencies>
-	
-	<productTypes>
-		<productType name="Firearms" />
-	</productTypes>
 
 	<products>
 		<product name="Pistol">
-			<type>Firearms</type>
 			<category>BASE</category>
 		</product>
 		<product name="Shotgun">
-			<type>Firearms</type>
 			<category>BASE</category>
 		</product>
 		<product name="Laser-Scope">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 	</products>
@@ -52,35 +46,35 @@
 				<product>Shotgun</product>
 			</tier>
 		</tiers>
-		<changeRule>
+		<changePolicyRule>
 			<qualifier>DEFAULT</qualifier>
 			<policy>END_OF_TERM</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>TERM_FROM_SHORT_TO_LONG</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>PRODUCT_FROM_LOW_TO_HIGH</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>PRODUCT_FROM_LOW_TO_HIGH</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeCase> 
+		</changePolicyRule>
+		<changePolicyCase> 
 			<fromBillingPeriod>MONTHLY</fromBillingPeriod>
 			<toProduct>Shotgun</toProduct>
 			<toBillingPeriod>MONTHLY</toBillingPeriod>
 			<policy>END_OF_TERM</policy>
-		</changeCase>
-		<changeCase> 
+		</changePolicyCase>
+		<changePolicyCase> 
 			<phaseType>TRIAL</phaseType>
 			<policy>IMMEDIATE</policy>
-		</changeCase>	
-		<alignmentCase>
+		</changePolicyCase>	
+		<changeAlignmentCase>
 			<alignment>START_OF_SUBSCRIPTION</alignment>
-		</alignmentCase>
+		</changeAlignmentCase>
 	</rules>
 
 	<plans>
@@ -107,7 +101,6 @@
 					<price><currency>USD</currency><value>29.95</value></price>								
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="shotgun-monthly">
 			<product>Shotgun</product>
@@ -133,7 +126,6 @@
 					<price><currency>GBP</currency><value>169.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="shotgun-annual">
 			<product>Shotgun</product>
@@ -158,7 +150,6 @@
 					<price><currency>GBP</currency><value>1699.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 	</plans>
 	<priceLists>
diff --git a/catalog/src/test/resources/WeaponsHire.xml b/catalog/src/test/resources/WeaponsHire.xml
index 292879d..59b9093 100644
--- a/catalog/src/test/resources/WeaponsHire.xml
+++ b/catalog/src/test/resources/WeaponsHire.xml
@@ -40,6 +40,7 @@ Use Cases to do:
 	xsi:noNamespaceSchemaLocation="../../main/resources/CatalogSchema.xsd ">
 
 	<effectiveDate>2011-10-08T00:00:00+00:00</effectiveDate>
+	<catalogName>Firearms</catalogName>
 
 	<currencies>
 		<currency>USD</currency>
@@ -47,14 +48,8 @@ Use Cases to do:
 		<currency>GBP</currency>
 	</currencies>
 	
-	<productTypes>
-		<productType name="Firearms" />
-		<productType name="Blade" />
-	</productTypes>
-
 	<products>
 		<product name="Pistol">
-			<type>Firearms</type>
 			<category>BASE</category>
 			<available>
 				<addonProduct>Telescopic-Scope</addonProduct>
@@ -62,11 +57,9 @@ Use Cases to do:
 			</available>
 		</product>
 		<product name="Shotgun">
-			<type>Firearms</type>
 			<category>BASE</category>
 		</product>
 		<product name="Assault-Rifle">
-			<type>Firearms</type>
 			<category>BASE</category>
 			<included> 
 				<addonProduct>Telescopic-Scope</addonProduct>
@@ -76,31 +69,24 @@ Use Cases to do:
 			</available>
 		</product>
 		<product name="Telescopic-Scope">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 		<product name="Laser-Scope">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 		<product name="Holster">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 		<product name="Extra-Ammo">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 		<product name="Refurbish-Maintenance">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 		<product name="Bowie-Knife">
-			<type>Blade</type>
 			<category>BASE</category>
 		</product>
 		<product name="Samuri-Sword">
-			<type>Blade</type>
 			<category>BASE</category>
 		</product>
 	</products>
@@ -113,51 +99,65 @@ Use Cases to do:
 				<product>Assault-Rifle</product>
 			</tier>
 		</tiers>
-		<changeRule>
+		<changePolicyRule>
 			<qualifier>DEFAULT</qualifier>
 			<policy>END_OF_TERM</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>TERM_FROM_SHORT_TO_LONG</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>PRODUCT_FROM_LOW_TO_HIGH</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeCase> 
+		</changePolicyRule>
+		<changePolicyCase> 
 			<fromBillingPeriod>MONTHLY</fromBillingPeriod>
 			<toProduct>Assault-Rifle</toProduct>
 			<toBillingPeriod>MONTHLY</toBillingPeriod>
 			<policy>END_OF_TERM</policy>
-		</changeCase>
-		<changeCase> 
+		</changePolicyCase>
+		<changePolicyCase> 
 			<toPriceList>rescue</toPriceList>
 			<policy>END_OF_TERM</policy>
-		</changeCase>		
-		<changeCase> 
-			<phaseType>TRIAL</phaseType>
-			<policy>IMMEDIATE</policy>
-		</changeCase>
-		<cancelCase>
-			<policy>END_OF_TERM</policy>
-		</cancelCase>
-		<cancelCase>
+		</changePolicyCase>		
+		<changePolicyCase> 
 			<phaseType>TRIAL</phaseType>
 			<policy>IMMEDIATE</policy>
-		</cancelCase>
-		<alignmentCase>
+		</changePolicyCase>
+		<changeAlignmentCase>
 			<alignment>START_OF_SUBSCRIPTION</alignment>
-		</alignmentCase>
-		<alignmentCase>
+		</changeAlignmentCase>
+		<changeAlignmentCase>
 			<toPriceList>rescue</toPriceList>
 			<alignment>CHANGE_OF_PLAN</alignment>
-		</alignmentCase>
-		<alignmentCase>
+		</changeAlignmentCase>
+		<changeAlignmentCase>
 			<fromPriceList>rescue</fromPriceList>
 			<toPriceList>rescue</toPriceList>
 			<alignment>CHANGE_OF_PRICELIST</alignment>
-		</alignmentCase>
+		</changeAlignmentCase>
+		<cancelPolicyCase>
+			<policy>END_OF_TERM</policy>
+		</cancelPolicyCase>
+		<cancelPolicyCase>
+			<phaseType>TRIAL</phaseType>
+			<policy>IMMEDIATE</policy>
+		</cancelPolicyCase>
+		<createAlignmentCase>
+			<alignment>START_OF_BUNDLE</alignment>
+		</createAlignmentCase>
+		<billingAlignmentCase>
+			<alignment>ACCOUNT</alignment>
+		</billingAlignmentCase>
+		<billingAlignmentCase>
+			<billingPeriod>ANNUAL</billingPeriod>
+			<alignment>SUBSCRIPTION</alignment>
+		</billingAlignmentCase>
+		<billingAlignmentCase>
+			<productCategory>ADD_ON</productCategory>
+			<alignment>BUNDLE</alignment>
+		</billingAlignmentCase>
 	</rules>
 
 	<plans>
@@ -184,7 +184,6 @@ Use Cases to do:
 					<price><currency>USD</currency><value>29.95</value></price>								
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="shotgun-monthly">
 			<product>Shotgun</product>
@@ -210,7 +209,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>169.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="assault-rifle-monthly">
 			<product>Assault-Rifle</product>
@@ -235,7 +233,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>399.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="pistol-annual">
 			<product>Pistol</product>
@@ -260,7 +257,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>199.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="shotgun-annual">
 			<product>Shotgun</product>
@@ -285,7 +281,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>1699.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="assault-rifle-annual">
 			<product>Assault-Rifle</product>
@@ -310,7 +305,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>3999.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="pistol-annual-gunclub-discount">
 			<product>Pistol</product>
@@ -347,7 +341,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>199.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="shotgun-annual-gunclub-discount">
 			<product>Shotgun</product>
@@ -384,7 +377,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>1699.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="assault-rifle-annual-gunclub-discount">
 			<product>Assault-Rifle</product>
@@ -421,7 +413,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>3999.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="laser-scope-monthly">
 		<product>Laser-Scope</product>
@@ -436,7 +427,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>1999.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>BUNDLE</billingAlignment>
 		</plan>
 		<plan name="telescopic-scope-monthly">
 			<product>Telescopic-Scope</product>
@@ -451,7 +441,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>999.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>BUNDLE</billingAlignment>
 		</plan>
 		<plan name="extra-ammo-monthly">
 			<product>Extra-Ammo</product>
@@ -466,7 +455,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>999.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>BUNDLE</billingAlignment>
 			<plansAllowedInBundle>-1</plansAllowedInBundle> <!-- arbitrary number of these (multipack) -->
 		</plan>
 		<plan name="holster-monthly-regular">
@@ -492,7 +480,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>199.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>BUNDLE</billingAlignment>
 		</plan>
 		<plan name="holster-monthly-special">
 			<product>Holster</product>
@@ -517,7 +504,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>199.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>BUNDLE</billingAlignment>
 		</plan>
 		<plan name="assault-rifle-annual-rescue">
 			<product>Assault-Rifle</product>
@@ -546,7 +532,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>3999.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="refurbish-maintenance">
 			<product>Refurbish-Maintenance</product>
@@ -567,7 +552,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>599.95</value></price>
 				</fixedPrice>
 			</finalPhase>
-			<billingAlignment>BUNDLE</billingAlignment>
 		</plan>
 	</plans>
 	<priceLists>
diff --git a/catalog/src/test/resources/WeaponsHireSmall.xml b/catalog/src/test/resources/WeaponsHireSmall.xml
index 9b8bbbc..a40f4c7 100644
--- a/catalog/src/test/resources/WeaponsHireSmall.xml
+++ b/catalog/src/test/resources/WeaponsHireSmall.xml
@@ -19,28 +19,22 @@
 	xsi:noNamespaceSchemaLocation="../../main/resources/CatalogSchema.xsd ">
 
 	<effectiveDate>2011-10-08T00:00:00+00:00</effectiveDate>
+	<catalogName>WeaponsHireSmall</catalogName>
 
 	<currencies>
 		<currency>USD</currency>
 		<currency>EUR</currency>
 		<currency>GBP</currency>
 	</currencies>
-	
-	<productTypes>
-		<productType name="Firearms" />
-	</productTypes>
 
 	<products>
 		<product name="Pistol">
-			<type>Firearms</type>
 			<category>BASE</category>
 		</product>
 		<product name="Shotgun">
-			<type>Firearms</type>
 			<category>BASE</category>
 		</product>
 		<product name="Laser-Scope">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 	</products>
@@ -52,35 +46,35 @@
 				<product>Shotgun</product>
 			</tier>
 		</tiers>
-		<changeRule>
+		<changePolicyRule>
 			<qualifier>DEFAULT</qualifier>
 			<policy>END_OF_TERM</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>TERM_FROM_SHORT_TO_LONG</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>PRODUCT_FROM_LOW_TO_HIGH</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>PRODUCT_FROM_LOW_TO_HIGH</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeCase> 
+		</changePolicyRule>
+		<changePolicyCase> 
 			<fromBillingPeriod>MONTHLY</fromBillingPeriod>
 			<toProduct>Shotgun</toProduct>
 			<toBillingPeriod>MONTHLY</toBillingPeriod>
 			<policy>END_OF_TERM</policy>
-		</changeCase>
-		<changeCase> 
+		</changePolicyCase>
+		<changePolicyCase> 
 			<phaseType>TRIAL</phaseType>
 			<policy>IMMEDIATE</policy>
-		</changeCase>	
-		<alignmentCase>
+		</changePolicyCase>	
+		<changeAlignmentCase>
 			<alignment>START_OF_SUBSCRIPTION</alignment>
-		</alignmentCase>
+		</changeAlignmentCase>
 	</rules>
 
 	<plans>
@@ -107,7 +101,6 @@
 					<price><currency>USD</currency><value>29.95</value></price>								
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="shotgun-monthly">
 			<product>Shotgun</product>
@@ -133,7 +126,6 @@
 					<price><currency>GBP</currency><value>169.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="shotgun-annual">
 			<product>Shotgun</product>
@@ -158,7 +150,6 @@
 					<price><currency>GBP</currency><value>1699.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 	</plans>
 	<priceLists>
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/IPlanAligner.java b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/IPlanAligner.java
new file mode 100644
index 0000000..ff57cf1
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/IPlanAligner.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.entitlement.alignment;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.IPlan;
+import com.ning.billing.catalog.api.IPlanPhase;
+import com.ning.billing.entitlement.api.user.Subscription;
+
+public interface IPlanAligner {
+
+
+    public final static class TimedPhase {
+
+        private final IPlanPhase phase;
+        private final DateTime startPhase;
+
+        public TimedPhase(IPlanPhase phase, DateTime startPhase) {
+            super();
+            this.phase = phase;
+            this.startPhase = startPhase;
+        }
+
+        public IPlanPhase getPhase() {
+            return phase;
+        }
+
+        public DateTime getStartPhase() {
+            return startPhase;
+        }
+    }
+
+    public TimedPhase getCurrentTimedPhaseOnCreate(Subscription subscription, IPlan plan,  String priceList, DateTime effectiveDate);
+
+    public TimedPhase getNextTimedPhaseOnCreate(Subscription subscription, IPlan plan,  String priceList, DateTime effectiveDate);
+
+    public TimedPhase getCurrentTimedPhaseOnChange(Subscription subscription, IPlan plan,  String priceList, DateTime effectiveDate);
+
+    public TimedPhase getNextTimedPhaseOnChange(Subscription subscription, IPlan plan,  String priceList, DateTime effectiveDate);
+
+    public TimedPhase getNextTimedPhase(Subscription subscription, IPlan plan, DateTime effectiveDate, DateTime planStartDate);
+
+
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
new file mode 100644
index 0000000..7856dab
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.entitlement.alignment;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.ICatalog;
+import com.ning.billing.catalog.api.IDuration;
+import com.ning.billing.catalog.api.IPlan;
+import com.ning.billing.catalog.api.IPlanPhase;
+import com.ning.billing.catalog.api.PlanAlignmentChange;
+import com.ning.billing.catalog.api.PlanAlignmentCreate;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PlanSpecifier;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.exceptions.EntitlementError;
+import com.ning.billing.util.clock.Clock;
+
+public class PlanAligner implements IPlanAligner {
+
+    // STEPH this is a bit broken right now until we figure out to retrieve ICatalog
+    private /*final*/ ICatalog catalog;
+
+    public PlanAligner() {
+        //this.catalog = Engine.getInstance().getCatalog();
+    }
+
+    public void init(ICatalog catalog) {
+        this.catalog = catalog;
+    }
+
+    private enum WhichPhase {
+        CURRENT,
+        NEXT
+    }
+
+    @Override
+    public TimedPhase getCurrentTimedPhaseOnCreate(Subscription subscription,
+            IPlan plan, String priceList, DateTime effectiveDate) {
+        return getTimedPhaseOnCreate(subscription, plan, priceList, effectiveDate, WhichPhase.CURRENT);
+    }
+
+    @Override
+    public TimedPhase getNextTimedPhaseOnCreate(Subscription subscription,
+            IPlan plan, String priceList, DateTime effectiveDate) {
+            return getTimedPhaseOnCreate(subscription, plan, priceList, effectiveDate, WhichPhase.NEXT);
+    }
+
+    @Override
+    public TimedPhase getCurrentTimedPhaseOnChange(Subscription subscription,
+            IPlan plan, String priceList, DateTime effectiveDate) {
+        return getTimedPhaseOnChange(subscription, plan, priceList, effectiveDate, WhichPhase.CURRENT);
+    }
+
+    @Override
+    public TimedPhase getNextTimedPhaseOnChange(Subscription subscription,
+            IPlan plan, String priceList, DateTime effectiveDate) {
+        return getTimedPhaseOnChange(subscription, plan, priceList, effectiveDate, WhichPhase.NEXT);
+    }
+
+
+
+    @Override
+    public TimedPhase getNextTimedPhase(Subscription subscription,
+            IPlan plan, DateTime effectiveDate, DateTime planStartDate) {
+        List<TimedPhase> timedPhases = getPhaseAlignments(subscription, plan, effectiveDate, planStartDate);
+        return getTimedPhase(timedPhases, effectiveDate, WhichPhase.NEXT);
+    }
+
+    private TimedPhase getTimedPhaseOnCreate(Subscription subscription,
+            IPlan plan, String priceList, DateTime effectiveDate, WhichPhase which) {
+
+            PlanSpecifier planSpecifier = new PlanSpecifier(plan.getProduct().getName(),
+                    plan.getProduct().getCategory(),
+                    plan.getBillingPeriod(),
+                    priceList);
+
+            DateTime planStartDate = null;
+            PlanAlignmentCreate alignement =  catalog.getPlanCreateAlignment(planSpecifier);
+            switch(alignement) {
+            case START_OF_SUBSCRIPTION:
+                planStartDate = subscription.getStartDate();
+                break;
+            case START_OF_BUNDLE:
+                planStartDate = subscription.getBundleStartDate();
+                break;
+            default:
+                throw new EntitlementError(String.format("Unknwon PlanAlignmentCreate %s", alignement));
+            }
+            List<TimedPhase> timedPhases = getPhaseAlignments(subscription, plan, effectiveDate, planStartDate);
+            return getTimedPhase(timedPhases, effectiveDate, which);
+    }
+
+    private TimedPhase getTimedPhaseOnChange(Subscription subscription,
+            IPlan plan, String priceList, DateTime effectiveDate, WhichPhase which) {
+
+        IPlanPhase currentPhase = subscription.getCurrentPhase();
+        IPlan currentPlan = subscription.getCurrentPlan();
+        String currentPriceList = subscription.getCurrentPriceList();
+
+        PlanPhaseSpecifier fromPlanPhaseSpecifier = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
+                currentPlan.getProduct().getCategory(),
+                currentPlan.getBillingPeriod(),
+                currentPriceList,
+                currentPhase.getPhaseType());
+
+        PlanSpecifier toPlanSpecifier = new PlanSpecifier(plan.getProduct().getName(),
+                plan.getProduct().getCategory(),
+                plan.getBillingPeriod(),
+                priceList);
+
+        DateTime planStartDate = null;
+        PlanAlignmentChange alignment = catalog.getPlanChangeAlignment(fromPlanPhaseSpecifier, toPlanSpecifier);
+        switch(alignment) {
+        case START_OF_SUBSCRIPTION:
+            planStartDate = subscription.getStartDate();
+            break;
+        case START_OF_BUNDLE:
+            planStartDate = subscription.getBundleStartDate();
+            break;
+        case CHANGE_OF_PLAN:
+            // STEPH
+            throw new EntitlementError(String.format("Not implemented yet %s", alignment));
+            //break;
+        case CHANGE_OF_PRICELIST:
+            // STEPH
+            throw new EntitlementError(String.format("Not implemented yet %s", alignment));
+            //break;
+        default:
+            throw new EntitlementError(String.format("Unknwon PlanAlignmentChange %s", alignment));
+        }
+        List<TimedPhase> timedPhases = getPhaseAlignments(subscription, plan, effectiveDate, planStartDate);
+        return getTimedPhase(timedPhases, effectiveDate, which);
+    }
+
+    private List<TimedPhase> getPhaseAlignments(Subscription subscription, IPlan plan,
+            DateTime effectiveDate, DateTime planStartDate) {
+
+        List<TimedPhase> result = new LinkedList<IPlanAligner.TimedPhase>();
+
+        DateTime curPhaseStart = planStartDate;
+        if (plan.getInitialPhases() == null) {
+            result.add(new TimedPhase(plan.getFinalPhase(), curPhaseStart));
+            return result;
+        }
+
+        DateTime nextPhaseStart = null;
+        for (IPlanPhase cur : plan.getInitialPhases()) {
+
+            result.add(new TimedPhase(cur, curPhaseStart));
+
+            IDuration curPhaseDuration = cur.getDuration();
+            nextPhaseStart = Clock.addDuration(curPhaseStart, curPhaseDuration);
+            if (nextPhaseStart == null) {
+                throw new EntitlementError(String.format("Unexpected non ending UNLIMITED phase for plan %s",
+                        plan.getName()));
+            }
+            curPhaseStart = nextPhaseStart;
+        }
+        result.add(new TimedPhase(plan.getFinalPhase(), nextPhaseStart));
+        return result;
+    }
+
+    private TimedPhase getTimedPhase(List<TimedPhase> timedPhases, DateTime effectiveDate, WhichPhase which) {
+        TimedPhase cur = null;
+        TimedPhase next = null;
+        for (TimedPhase phase : timedPhases) {
+            if (phase.getStartPhase().isAfter(effectiveDate)) {
+                next = phase;
+                break;
+            }
+            cur = phase;
+        }
+        switch(which) {
+        case CURRENT:
+            return cur;
+        case NEXT:
+            return next;
+        default:
+            throw new EntitlementError(String.format("Unepected %s TimedPhase", which));
+        }
+    }
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
index 9e7e154..ebb180e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
@@ -33,14 +33,16 @@ import com.ning.billing.catalog.api.ICatalog;
 import com.ning.billing.catalog.api.IPlan;
 import com.ning.billing.catalog.api.IPlanPhase;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PlanSpecifier;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.alignment.EntitlementAlignment;
-import com.ning.billing.entitlement.api.user.ISubscription.SubscriptionState;
+import com.ning.billing.entitlement.alignment.IPlanAligner;
+import com.ning.billing.entitlement.alignment.IPlanAligner.TimedPhase;
 import com.ning.billing.entitlement.engine.core.Engine;
 import com.ning.billing.entitlement.engine.dao.IEntitlementDao;
 import com.ning.billing.entitlement.events.IEvent;
 import com.ning.billing.entitlement.events.IEvent.EventType;
 import com.ning.billing.entitlement.events.phase.IPhaseEvent;
+import com.ning.billing.entitlement.events.phase.PhaseEvent;
 import com.ning.billing.entitlement.events.user.ApiEventCancel;
 import com.ning.billing.entitlement.events.user.ApiEventChange;
 import com.ning.billing.entitlement.events.user.ApiEventType;
@@ -61,6 +63,7 @@ public class Subscription extends PrivateFields  implements ISubscription {
     private final IClock clock;
     private final IEntitlementDao dao;
     private final ICatalog catalog;
+    private final IPlanAligner planAligner;
 
     // STEPH interaction with billing /payment system
     private final DateTime chargedThroughDate;
@@ -148,7 +151,7 @@ public class Subscription extends PrivateFields  implements ISubscription {
         this.clock = engine.getClock();
         this.dao = engine.getDao();
         this.catalog = engine.getCatalog();
-
+        this.planAligner = engine.getPlanAligner();
         this.id = id;
         this.bundleId = bundleId;
         this.startDate = startDate;
@@ -218,8 +221,13 @@ public class Subscription extends PrivateFields  implements ISubscription {
 
         DateTime now = clock.getUTCNow();
 
-        PlanPhaseSpecifier planPhase = new PlanPhaseSpecifier(getCurrentPlan().getProduct().getName(),
-        		getCurrentPlan().getBillingPeriod(), getCurrentPriceList(), getCurrentPhase().getPhaseType());
+        IPlan currentPlan = getCurrentPlan();
+        PlanPhaseSpecifier planPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
+                currentPlan.getProduct().getCategory(),
+        		getCurrentPlan().getBillingPeriod(),
+        		getCurrentPriceList(),
+        		getCurrentPhase().getPhaseType());
+
         ActionPolicy policy = catalog.getPlanCancelPolicy(planPhase);
         DateTime effectiveDate = getPlanChangeEffectiveDate(policy, now);
         IEvent cancelEvent = new ApiEventCancel(id, bundleStartDate, now, now, effectiveDate, activeVersion);
@@ -237,10 +245,9 @@ public class Subscription extends PrivateFields  implements ISubscription {
         List<IEvent> uncancelEvents = new ArrayList<IEvent>();
         uncancelEvents.add(uncancelEvent);
 
-        // Recalculate Plan alignment for next phase event
-        EntitlementAlignment planPhaseAlignment = new EntitlementAlignment(id, now, bundleStartDate, getCurrentPlan(),
-                now, activeVersion);
-        IPhaseEvent nextPhaseEvent = planPhaseAlignment.getNextPhaseEvent();
+        DateTime planStartDate = getCurrentPlanStart();
+        TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(this, getCurrentPlan(), now, planStartDate);
+        IPhaseEvent nextPhaseEvent = PhaseEvent.getNextPhaseEvent(nextTimedPhase, this, now);
         if (nextPhaseEvent != null) {
             uncancelEvents.add(nextPhaseEvent);
         }
@@ -271,20 +278,25 @@ public class Subscription extends PrivateFields  implements ISubscription {
                     productName, term.toString(), realPriceList);
         }
 
-        PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(getCurrentPlan().getProduct().getName(),
-        		getCurrentPlan().getBillingPeriod(),
+        IPlan currentPlan = getCurrentPlan();
+        PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
+        		currentPlan.getProduct().getCategory(),
+                currentPlan.getBillingPeriod(),
         		currentPriceList, getCurrentPhase().getPhaseType());
-        PlanPhaseSpecifier toPlanPhase = new PlanPhaseSpecifier(newPlan.getProduct().getName(),
+        PlanSpecifier toPlanPhase = new PlanSpecifier(newPlan.getProduct().getName(),
+                newPlan.getProduct().getCategory(),
         		newPlan.getBillingPeriod(),
-        		realPriceList, null);
+        		realPriceList);
 
         ActionPolicy policy = catalog.getPlanChangePolicy(fromPlanPhase, toPlanPhase);
         DateTime effectiveDate = getPlanChangeEffectiveDate(policy, now);
-        IEvent changeEvent = new ApiEventChange(id, bundleStartDate, now, newPlan, realPriceList, now, effectiveDate, activeVersion);
 
-        EntitlementAlignment planPhaseAlignment = new EntitlementAlignment(id, now, bundleStartDate, newPlan,
-                effectiveDate, activeVersion);
-        IPhaseEvent nextPhaseEvent = planPhaseAlignment.getNextPhaseEvent();
+        TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(this, newPlan, realPriceList, effectiveDate);
+        IEvent changeEvent = new ApiEventChange(id, bundleStartDate, now, newPlan.getName(), currentTimedPhase.getPhase().getName(),
+                realPriceList, now, effectiveDate, activeVersion);
+
+        TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(this, newPlan, realPriceList, effectiveDate);
+        IPhaseEvent nextPhaseEvent = PhaseEvent.getNextPhaseEvent(nextTimedPhase, this, now);
         List<IEvent> changeEvents = new ArrayList<IEvent>();
         // Add phase event first so we expect to see PHASE event first-- mostly for test expectation
         if (nextPhaseEvent != null) {
@@ -341,6 +353,28 @@ public class Subscription extends PrivateFields  implements ISubscription {
         return paidThroughDate;
     }
 
+    public DateTime getCurrentPlanStart() {
+
+        if (transitions == null) {
+            throw new EntitlementError(String.format("No transitions for subscription %s", getId()));
+        }
+
+        Iterator<SubscriptionTransition> it = ((LinkedList<SubscriptionTransition>) transitions).descendingIterator();
+        while (it.hasNext()) {
+            SubscriptionTransition cur = it.next();
+            if (cur.getTransitionTime().isAfter(clock.getUTCNow())) {
+                // Skip future events
+                continue;
+            }
+            if (cur.getEventType() == EventType.API_USER &&
+                    cur.getApiEventType() == ApiEventType.CHANGE) {
+                return cur.getTransitionTime();
+            }
+        }
+        // CREATE event
+        return transitions.get(0).getTransitionTime();
+    }
+
     public List<ISubscriptionTransition> getActiveTransitions() {
         if (transitions == null) {
             return null;
@@ -380,7 +414,7 @@ public class Subscription extends PrivateFields  implements ISubscription {
         for (SubscriptionTransition cur : transitions) {
             if (cur.getTransitionTime().isBefore(clock.getUTCNow()) ||
                     cur.getEventType() == EventType.PHASE ||
-                        cur.getApiEventType() != ApiEventType.CHANGE) {
+                    cur.getApiEventType() != ApiEventType.CHANGE) {
                 continue;
             }
             return true;
@@ -407,6 +441,7 @@ public class Subscription extends PrivateFields  implements ISubscription {
         return effectiveDate;
     }
 
+
     private DateTime getCurrentPhaseStart() {
 
         if (transitions == null) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/UserApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/UserApi.java
index a922486..bbf147f 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/UserApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/UserApi.java
@@ -29,8 +29,8 @@ import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.ICatalog;
 import com.ning.billing.catalog.api.IPlan;
 import com.ning.billing.catalog.api.IPlanPhase;
-import com.ning.billing.entitlement.alignment.EntitlementAlignment;
-import com.ning.billing.entitlement.alignment.EntitlementAlignment.TimedPhase;
+import com.ning.billing.entitlement.alignment.IPlanAligner;
+import com.ning.billing.entitlement.alignment.IPlanAligner.TimedPhase;
 import com.ning.billing.entitlement.api.user.IApiListener;
 import com.ning.billing.entitlement.api.user.ISubscription;
 import com.ning.billing.entitlement.api.user.ISubscriptionBundle;
@@ -50,13 +50,15 @@ public class UserApi implements IUserApi {
     private final IClock clock;
     private final IEntitlementDao dao;
     private final ICatalog catalog;
+    private final IPlanAligner planAligner;
 
     @Inject
-    public UserApi(Engine engine, IClock clock, IEntitlementDao dao) {
+    public UserApi(Engine engine, IClock clock, IPlanAligner planAligner, IEntitlementDao dao) {
         super();
         this.engine = engine;
         this.clock = clock;
         this.dao = dao;
+        this.planAligner = planAligner;
         this.catalog = engine.getCatalog();
     }
 
@@ -139,14 +141,17 @@ public class UserApi implements IUserApi {
                      plan.getProduct().getCategory().toString()));
         }
 
-        Subscription subscription = new Subscription(bundleId, plan.getProduct().getCategory(), bundleStartDate, now);
+        DateTime effectiveDate = now;
+
+        Subscription subscription = new Subscription(bundleId, plan.getProduct().getCategory(), bundleStartDate, effectiveDate);
+
+        TimedPhase currentTimedPhase =  planAligner.getCurrentTimedPhaseOnCreate(subscription, plan, realPriceList, effectiveDate);
         ApiEventCreate creationEvent =
-            new ApiEventCreate(subscription.getId(), bundleStartDate, now, plan, realPriceList,
-                    now, now, subscription.getActiveVersion());
+            new ApiEventCreate(subscription.getId(), bundleStartDate, now, plan.getName(), currentTimedPhase.getPhase().getName(), realPriceList,
+                    now, effectiveDate, subscription.getActiveVersion());
 
-        EntitlementAlignment planPhaseAlignment = new EntitlementAlignment(subscription.getId(), now,
-                bundleStartDate, plan, now, subscription.getActiveVersion());
-        IPhaseEvent nextPhaseEvent = planPhaseAlignment.getNextPhaseEvent();
+        TimedPhase nextTimedPhase =  planAligner.getNextTimedPhaseOnCreate(subscription, plan, realPriceList, effectiveDate);
+        IPhaseEvent nextPhaseEvent = PhaseEvent.getNextPhaseEvent(nextTimedPhase, subscription, now);
         List<IEvent> events = new ArrayList<IEvent>();
         events.add(creationEvent);
         if (nextPhaseEvent != null) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/ApiEventProcessor.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/ApiEventProcessor.java
index fdbaefb..437f21c 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/ApiEventProcessor.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/ApiEventProcessor.java
@@ -21,13 +21,13 @@ import java.util.List;
 import com.google.inject.Inject;
 import com.ning.billing.entitlement.engine.dao.IEntitlementDao;
 import com.ning.billing.entitlement.events.IEvent;
-import com.ning.billing.entitlement.glue.IEngineConfig;
+import com.ning.billing.entitlement.glue.IEntitlementConfig;
 import com.ning.billing.util.clock.IClock;
 
 public class ApiEventProcessor extends ApiEventProcessorBase {
 
     @Inject
-    public ApiEventProcessor(IClock clock, IEntitlementDao dao, IEngineConfig config) {
+    public ApiEventProcessor(IClock clock, IEntitlementDao dao, IEntitlementConfig config) {
         super(clock, dao, config);
     }
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/ApiEventProcessorBase.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/ApiEventProcessorBase.java
index c198226..b83b0be 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/ApiEventProcessorBase.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/ApiEventProcessorBase.java
@@ -31,7 +31,7 @@ import org.slf4j.LoggerFactory;
 import com.google.inject.Inject;
 import com.ning.billing.entitlement.engine.dao.IEntitlementDao;
 import com.ning.billing.entitlement.events.IEvent;
-import com.ning.billing.entitlement.glue.IEngineConfig;
+import com.ning.billing.entitlement.glue.IEntitlementConfig;
 import com.ning.billing.util.clock.IClock;
 
 public abstract class ApiEventProcessorBase implements IApiEventProcessor {
@@ -51,14 +51,14 @@ public abstract class ApiEventProcessorBase implements IApiEventProcessor {
     protected final IClock clock;
 
     private Executor executor;
-    private final IEngineConfig config;
+    private final IEntitlementConfig config;
     protected IEventListener listener;
 
     protected long nbProcessedEvents;
     protected volatile boolean isProcessingEvents;
 
     @Inject
-    public ApiEventProcessorBase(IClock clock, IEntitlementDao dao, IEngineConfig config) {
+    public ApiEventProcessorBase(IClock clock, IEntitlementDao dao, IEntitlementConfig config) {
         this.clock = clock;
         this.dao = dao;
         this.config = config;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
index 62bbae2..2511884 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
@@ -27,8 +27,10 @@ import com.google.inject.Inject;
 import com.ning.billing.catalog.api.ICatalog;
 import com.ning.billing.catalog.api.ICatalogUserApi;
 import com.ning.billing.catalog.api.IPlan;
-import com.ning.billing.entitlement.alignment.EntitlementAlignment;
-import com.ning.billing.entitlement.alignment.EntitlementAlignment.TimedPhase;
+
+import com.ning.billing.entitlement.alignment.IPlanAligner;
+import com.ning.billing.entitlement.alignment.IPlanAligner.TimedPhase;
+import com.ning.billing.entitlement.alignment.PlanAligner;
 import com.ning.billing.entitlement.api.user.IApiListener;
 import com.ning.billing.entitlement.api.user.ISubscription;
 import com.ning.billing.entitlement.api.user.Subscription;
@@ -39,7 +41,7 @@ import com.ning.billing.entitlement.events.phase.IPhaseEvent;
 import com.ning.billing.entitlement.events.phase.PhaseEvent;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 import com.ning.billing.entitlement.events.user.IUserEvent;
-import com.ning.billing.entitlement.glue.IEngineConfig;
+import com.ning.billing.entitlement.glue.IEntitlementConfig;
 import com.ning.billing.util.clock.IClock;
 
 public class Engine implements IEventListener {
@@ -52,19 +54,25 @@ public class Engine implements IEventListener {
     private final IEntitlementDao dao;
     private final IApiEventProcessor apiEventProcessor;
     private final ICatalogUserApi catalogApi;
+    private final IPlanAligner planAligner;
 
     private List<IApiListener> observers;
 
     @Inject
-    public Engine(IClock clock, IEntitlementDao dao, IApiEventProcessor apiEventProcessor, ICatalogUserApi catalogApi, IEngineConfig config) {
+    public Engine(IClock clock, IEntitlementDao dao, IApiEventProcessor apiEventProcessor, ICatalogUserApi catalogApi,
+            IPlanAligner planAligner, IEntitlementConfig config) {
         super();
         this.clock = clock;
         this.catalogApi = catalogApi;
         this.dao = dao;
         this.apiEventProcessor = apiEventProcessor;
+        this.planAligner = planAligner;
         this.catalog = readCatalogFromConfig(config.getCatalogConfigFileName());
         this.observers = null;
         instance = this;
+
+        // STEPH yack
+        ((PlanAligner) planAligner).init(catalog);
     }
 
     public void start() {
@@ -126,11 +134,8 @@ public class Engine implements IEventListener {
 
         DateTime now = clock.getUTCNow();
 
-
-        EntitlementAlignment planPhaseAlignment = new EntitlementAlignment(subscription.getId(),
-                now, subscription.getBundleStartDate(), subscription.getCurrentPlan(),
-                subscription.getLatestTranstion().getTransitionTime(), subscription.getActiveVersion());
-        IPhaseEvent nextPhaseEvent = planPhaseAlignment.getNextPhaseEvent();
+        TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, subscription.getCurrentPlan(), now, subscription.getCurrentPlanStart());
+        IPhaseEvent nextPhaseEvent = PhaseEvent.getNextPhaseEvent(nextTimedPhase, subscription, now);
         if (nextPhaseEvent != null) {
             // STEPH Harden since event could be processed twice
             dao.createNextPhaseEvent(subscription.getId(), nextPhaseEvent);
@@ -163,4 +168,8 @@ public class Engine implements IEventListener {
         return dao;
     }
 
+    public IPlanAligner getPlanAligner() {
+        return planAligner;
+    }
+
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
index 65a7cdb..ddeaf00 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
@@ -42,7 +42,7 @@ import com.ning.billing.entitlement.events.IEvent.EventType;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 import com.ning.billing.entitlement.events.user.IUserEvent;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
-import com.ning.billing.entitlement.glue.IEngineConfig;
+import com.ning.billing.entitlement.glue.IEntitlementConfig;
 import com.ning.billing.util.Hostname;
 import com.ning.billing.util.clock.IClock;
 
@@ -54,11 +54,11 @@ public class EntitlementDao implements IEntitlementDao {
     private final ISubscriptionSqlDao subscriptionsDao;
     private final IBundleSqlDao bundlesDao;
     private final IEventSqlDao eventsDao;
-    private final IEngineConfig config;
+    private final IEntitlementConfig config;
     private final String hostname;
 
     @Inject
-    public EntitlementDao(DBI dbi, IClock clock, IEngineConfig config) {
+    public EntitlementDao(DBI dbi, IClock clock, IEntitlementConfig config) {
         this.clock = clock;
         this.config = config;
         this.subscriptionsDao = dbi.onDemand(ISubscriptionSqlDao.class);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/phase/PhaseEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/phase/PhaseEvent.java
index f57ac4a..9c6bbba 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/phase/PhaseEvent.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/phase/PhaseEvent.java
@@ -22,6 +22,8 @@ import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.IPlan;
 import com.ning.billing.catalog.api.IPlanPhase;
+import com.ning.billing.entitlement.alignment.IPlanAligner.TimedPhase;
+import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.events.EventBase;
 import com.ning.billing.entitlement.events.IEventLyfecycle.IEventLyfecycleState;
 
@@ -71,4 +73,12 @@ public class PhaseEvent extends EventBase implements IPhaseEvent {
                 + ", isActive()=" + isActive() + "]\n";
     }
 
+    public static final IPhaseEvent getNextPhaseEvent(TimedPhase nextTimedPhase, Subscription subscription, DateTime now) {
+        return (nextTimedPhase == null) ?
+                null :
+                    new PhaseEvent(subscription.getId(), nextTimedPhase.getPhase(), now, nextTimedPhase.getStartPhase(),
+                            now,  subscription.getActiveVersion());
+
+    }
+
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java
index 6a06aa8..4e2944e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java
@@ -21,7 +21,9 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.IPlan;
-import com.ning.billing.entitlement.alignment.EntitlementAlignment;
+import com.ning.billing.entitlement.alignment.IPlanAligner;
+import com.ning.billing.entitlement.alignment.PlanAligner;
+import com.ning.billing.entitlement.engine.core.Engine;
 import com.ning.billing.entitlement.events.EventBase;
 import com.ning.billing.entitlement.events.IEventLyfecycle.IEventLyfecycleState;
 
@@ -34,15 +36,25 @@ public class ApiEventBase extends EventBase implements IUserEvent {
     private final String eventPriceList;
 
 
-    public ApiEventBase(UUID subscriptionId, DateTime bundleStartDate, DateTime processed, IPlan eventPlan,
+    public ApiEventBase(UUID subscriptionId, DateTime bundleStartDate, DateTime processed, String planName, String phaseName,
             String priceList, DateTime requestedDate,  ApiEventType eventType, DateTime effectiveDate, long activeVersion) {
         super(subscriptionId, requestedDate, effectiveDate, processed, activeVersion, true);
         this.eventType = eventType;
         this.eventPriceList = priceList;
-        this.eventPlan = (eventPlan != null) ? eventPlan.getName() : null;
-        this.eventPlanPhase = (eventPlan != null) ? getPhaseName(eventPlan, bundleStartDate, effectiveDate) : null;
+        this.eventPlan = planName;
+        this.eventPlanPhase = phaseName;
     }
 
+    public ApiEventBase(UUID subscriptionId, DateTime bundleStartDate, DateTime processed,
+            DateTime requestedDate,  ApiEventType eventType, DateTime effectiveDate, long activeVersion) {
+        super(subscriptionId, requestedDate, effectiveDate, processed, activeVersion, true);
+        this.eventType = eventType;
+        this.eventPriceList = null;
+        this.eventPlan = null;
+        this.eventPlanPhase = null;
+    }
+
+
     public ApiEventBase(UUID id, UUID subscriptionId, DateTime processed, String eventPlan, String eventPhase,
             String priceList, DateTime requestedDate,  ApiEventType eventType, DateTime effectiveDate, long activeVersion,
             boolean isActive, UUID processingOwner, DateTime nextAvailableProcessingTime,IEventLyfecycleState processingState) {
@@ -97,15 +109,4 @@ public class ApiEventBase extends EventBase implements IUserEvent {
                 + ", getSubscriptionId()=" + getSubscriptionId()
                 + ", isActive()=" + isActive() + "]";
     }
-
-    private String getPhaseName(IPlan eventPlan, DateTime bundleStartDate, DateTime effectiveDate) {
-
-        if (eventType != ApiEventType.CREATE && eventType != ApiEventType.CHANGE) {
-            return null;
-        }
-        EntitlementAlignment align = new EntitlementAlignment(bundleStartDate, eventPlan, effectiveDate);
-        return align.getCurrentTimedPhase().getPhase().getName();
-     }
-
-
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventCancel.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventCancel.java
index 1ea1b57..a3806d2 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventCancel.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventCancel.java
@@ -26,7 +26,7 @@ import com.ning.billing.entitlement.events.IEventLyfecycle.IEventLyfecycleState;
 public class ApiEventCancel extends ApiEventBase {
 
     public ApiEventCancel(UUID subscriptionId, DateTime bundleStartDate, DateTime now, DateTime requestedDate, DateTime effectiveDate, long version) {
-        super(subscriptionId, bundleStartDate, now, null, null, requestedDate, ApiEventType.CANCEL, effectiveDate, version);
+        super(subscriptionId, bundleStartDate, now, requestedDate, ApiEventType.CANCEL, effectiveDate, version);
     }
 
     public ApiEventCancel(UUID id, UUID subscriptionId, DateTime processed, String eventPlan, String eventPhase,
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventChange.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventChange.java
index bdb0a38..40584f5 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventChange.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventChange.java
@@ -27,8 +27,9 @@ import com.ning.billing.entitlement.events.IEventLyfecycle.IEventLyfecycleState;
 
 public class ApiEventChange extends ApiEventBase {
 
-    public ApiEventChange(UUID subscriptionId,  DateTime bundleStartDate, DateTime now, IPlan eventPlan, String priceList, DateTime requestedDate, DateTime effectiveDate, long version) {
-        super(subscriptionId, bundleStartDate, now, eventPlan, priceList, requestedDate, ApiEventType.CHANGE, effectiveDate, version);
+    public ApiEventChange(UUID subscriptionId,  DateTime bundleStartDate, DateTime now, String planName, String phaseName, String priceList,
+            DateTime requestedDate, DateTime effectiveDate, long version) {
+        super(subscriptionId, bundleStartDate, now, planName, phaseName, priceList, requestedDate, ApiEventType.CHANGE, effectiveDate, version);
     }
 
     public ApiEventChange(UUID id, UUID subscriptionId, DateTime processed, String eventPlan, String eventPhase, String priceList,
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventCreate.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventCreate.java
index 3b2588b..2b12e7e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventCreate.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventCreate.java
@@ -26,9 +26,9 @@ import com.ning.billing.entitlement.events.IEventLyfecycle.IEventLyfecycleState;
 public class ApiEventCreate extends ApiEventBase {
 
 
-    public ApiEventCreate(UUID subscriptionId, DateTime bundleStartDate, DateTime now, IPlan eventPlan, String priceList,
+    public ApiEventCreate(UUID subscriptionId, DateTime bundleStartDate, DateTime now, String planName, String phaseName, String priceList,
             DateTime requestedDate, DateTime effectiveDate, long version) {
-        super(subscriptionId, bundleStartDate, now, eventPlan, priceList, requestedDate, ApiEventType.CREATE, effectiveDate, version);
+        super(subscriptionId, bundleStartDate, now, planName, phaseName, priceList, requestedDate, ApiEventType.CREATE, effectiveDate, version);
     }
 
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventPause.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventPause.java
index cd70804..a6ff4b4 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventPause.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventPause.java
@@ -27,7 +27,7 @@ import com.ning.billing.entitlement.events.IEventLyfecycle.IEventLyfecycleState;
 public class ApiEventPause extends ApiEventBase {
 
     public ApiEventPause(UUID subscriptionId, DateTime now, DateTime requestedDate, DateTime effectiveDate, long version) {
-        super(subscriptionId, null, now, null, null, requestedDate, ApiEventType.PAUSE, effectiveDate, version);
+        super(subscriptionId, null, now, requestedDate, ApiEventType.PAUSE, effectiveDate, version);
     }
 
     public ApiEventPause(UUID id, UUID subscriptionId, DateTime processed, String eventPlan, String eventPhase,
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventResume.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventResume.java
index 05a2461..f8bf26f 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventResume.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventResume.java
@@ -28,7 +28,7 @@ import com.ning.billing.entitlement.events.IEventLyfecycle.IEventLyfecycleState;
 public class ApiEventResume extends ApiEventBase {
 
     public ApiEventResume(UUID subscriptionId, DateTime now, DateTime requestedDate, DateTime effectiveDate, long version) {
-        super(subscriptionId, null, now, null, null, requestedDate, ApiEventType.RESUME, effectiveDate, version);
+        super(subscriptionId, null, now, requestedDate, ApiEventType.RESUME, effectiveDate, version);
     }
 
     public ApiEventResume(UUID id, UUID subscriptionId, DateTime processed, String eventPlan, String eventPhase,
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventUncancel.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventUncancel.java
index a5c75a8..b5433f1 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventUncancel.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventUncancel.java
@@ -24,7 +24,7 @@ import org.joda.time.DateTime;
 public class ApiEventUncancel extends ApiEventBase {
 
     public ApiEventUncancel(UUID subscriptionId, DateTime bundleStartDate, DateTime now, DateTime requestedDate, DateTime effectiveDate, long version) {
-        super(subscriptionId, bundleStartDate, now, null, null, requestedDate, ApiEventType.UNCANCEL, effectiveDate, version);
+        super(subscriptionId, bundleStartDate, now, requestedDate, ApiEventType.UNCANCEL, effectiveDate, version);
     }
 
     public ApiEventUncancel(UUID id, UUID subscriptionId, DateTime processed, String eventPlan, String eventPhase,
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/ApiTestListener.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/ApiTestListener.java
index 6433911..9591ee6 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/ApiTestListener.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/ApiTestListener.java
@@ -62,7 +62,7 @@ public class ApiTestListener implements IApiListener {
             }
         }
         if (!completed) {
-            log.warn("ApiTestListener did not complete in " + timeout + " ms");
+            log.debug("ApiTestListener did not complete in " + timeout + " ms");
         }
         return completed;
     }
@@ -72,15 +72,15 @@ public class ApiTestListener implements IApiListener {
     }
 
     private void notifyIfStackEmpty() {
-        log.info("notifyIfStackEmpty ENTER");
+        log.debug("notifyIfStackEmpty ENTER");
         synchronized (this) {
             if (nextExpectedEvent.isEmpty()) {
-                log.info("notifyIfStackEmpty EMPTY");
+                log.debug("notifyIfStackEmpty EMPTY");
                 completed = true;
                 notify();
             }
         }
-        log.info("notifyIfStackEmpty EXIT");
+        log.debug("notifyIfStackEmpty EXIT");
     }
 
     private void assertEqualsNicely(NextEvent expected, NextEvent real) {
@@ -100,35 +100,35 @@ public class ApiTestListener implements IApiListener {
 
     @Override
     public void subscriptionCreated(ISubscriptionTransition created) {
-        log.info("-> Got event CREATED");
+        log.debug("-> Got event CREATED");
         assertEqualsNicely(nextExpectedEvent.pop(), NextEvent.CREATE);
         notifyIfStackEmpty();
     }
 
     @Override
     public void subscriptionCancelled(ISubscriptionTransition cancelled) {
-        log.info("-> Got event CANCEL");
+        log.debug("-> Got event CANCEL");
         assertEqualsNicely(nextExpectedEvent.pop(), NextEvent.CANCEL);
         notifyIfStackEmpty();
     }
 
     @Override
     public void subscriptionChanged(ISubscriptionTransition changed) {
-        log.info("-> Got event CHANGE");
+        log.debug("-> Got event CHANGE");
         assertEqualsNicely(nextExpectedEvent.pop(), NextEvent.CHANGE);
         notifyIfStackEmpty();
     }
 
     @Override
     public void subscriptionPaused(ISubscriptionTransition paused) {
-        log.info("-> Got event PAUSE");
+        log.debug("-> Got event PAUSE");
         assertEqualsNicely(nextExpectedEvent.pop(), NextEvent.PAUSE);
         notifyIfStackEmpty();
     }
 
     @Override
     public void subscriptionResumed(ISubscriptionTransition resumed) {
-        log.info("-> Got event RESUME");
+        log.debug("-> Got event RESUME");
         assertEqualsNicely(nextExpectedEvent.pop(), NextEvent.RESUME);
         notifyIfStackEmpty();
     }
@@ -136,7 +136,7 @@ public class ApiTestListener implements IApiListener {
     @Override
     public void subscriptionPhaseChanged(
             ISubscriptionTransition phaseChanged) {
-        log.info("-> Got event PHASE");
+        log.debug("-> Got event PHASE");
         assertEqualsNicely(nextExpectedEvent.pop(), NextEvent.PHASE);
         notifyIfStackEmpty();
     }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiBase.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiBase.java
index 95a5b51..bc4adc5 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiBase.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiBase.java
@@ -55,7 +55,7 @@ import com.ning.billing.entitlement.events.IEvent;
 import com.ning.billing.entitlement.events.phase.IPhaseEvent;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 import com.ning.billing.entitlement.events.user.IUserEvent;
-import com.ning.billing.entitlement.glue.IEngineConfig;
+import com.ning.billing.entitlement.glue.IEntitlementConfig;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.clock.IClock;
 
@@ -69,7 +69,7 @@ public abstract class TestUserApiBase {
     protected IUserApi entitlementApi;
     protected IBillingApi billingApi;
     protected ICatalogUserApi catalogApi;
-    protected IEngineConfig config;
+    protected IEntitlementConfig config;
     protected IEntitlementDao dao;
     protected ClockMock clock;
 
@@ -109,7 +109,7 @@ public abstract class TestUserApiBase {
         entitlementApi = g.getInstance(IUserApi.class);
         catalogApi = g.getInstance(ICatalogUserApi.class);
         billingApi = g.getInstance(IBillingApi.class);
-        config = g.getInstance(IEngineConfig.class);
+        config = g.getInstance(IEntitlementConfig.class);
         dao = g.getInstance(IEntitlementDao.class);
         clock = (ClockMock) g.getInstance(IClock.class);
         try {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
index 6a07d25..8816503 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
@@ -37,7 +37,7 @@ import com.ning.billing.catalog.api.IDuration;
 import com.ning.billing.catalog.api.IPlan;
 import com.ning.billing.catalog.api.IPlanPhase;
 import com.ning.billing.catalog.api.PhaseType;
-import com.ning.billing.catalog.api.PlanAlignment;
+import com.ning.billing.catalog.api.PlanAlignmentChange;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
 import com.ning.billing.entitlement.events.IEvent;
@@ -211,11 +211,11 @@ public abstract class TestUserApiChangePlan extends TestUserApiBase {
     }
 
 
-    protected void testChangePlanSubscriptionAlignEOTWithChargeThroughDateReal() {
-        tChangePlanSubscriptionAlignEOTWithChargeThroughDate("Shotgun", BillingPeriod.ANNUAL, "standard", "Assault-Rifle", BillingPeriod.ANNUAL, "rescue");
+    protected void testChangePlanChangePlanAlignEOTWithChargeThroughDateReal() {
+        tChangePlanChangePlanAlignEOTWithChargeThroughDate("Shotgun", BillingPeriod.ANNUAL, "standard", "Assault-Rifle", BillingPeriod.ANNUAL, "rescue");
     }
 
-    private void tChangePlanSubscriptionAlignEOTWithChargeThroughDate(String fromProd, BillingPeriod fromTerm, String fromPlanSet,
+    private void tChangePlanChangePlanAlignEOTWithChargeThroughDate(String fromProd, BillingPeriod fromTerm, String fromPlanSet,
             String toProd, BillingPeriod toTerm, String toPlanSet) {
 
         log.info("Starting testChangePlanBundleAlignEOTWithChargeThroughDate");
@@ -328,7 +328,6 @@ public abstract class TestUserApiChangePlan extends TestUserApiBase {
             assertNotNull(currentPlan);
             assertEquals(currentPlan.getProduct().getName(), "Assault-Rifle");
             assertEquals(currentPlan.getProduct().getCategory(), ProductCategory.BASE);
-            assertEquals(currentPlan.getPlanAlignment(), PlanAlignment.START_OF_BUNDLE);
             assertEquals(currentPlan.getBillingPeriod(), BillingPeriod.ANNUAL);
 
             IPlanPhase currentPhase = subscription.getCurrentPhase();
@@ -379,7 +378,6 @@ public abstract class TestUserApiChangePlan extends TestUserApiBase {
             assertNotNull(currentPlan);
             assertEquals(currentPlan.getProduct().getName(), "Assault-Rifle");
             assertEquals(currentPlan.getProduct().getCategory(), ProductCategory.BASE);
-            assertEquals(currentPlan.getPlanAlignment(), PlanAlignment.START_OF_BUNDLE);
             assertEquals(currentPlan.getBillingPeriod(), BillingPeriod.ANNUAL);
 
             IPlanPhase currentPhase = subscription.getCurrentPhase();
@@ -397,7 +395,6 @@ public abstract class TestUserApiChangePlan extends TestUserApiBase {
             assertNotNull(currentPlan);
             assertEquals(currentPlan.getProduct().getName(), "Pistol");
             assertEquals(currentPlan.getProduct().getCategory(), ProductCategory.BASE);
-            assertEquals(currentPlan.getPlanAlignment(), PlanAlignment.START_OF_BUNDLE);
             assertEquals(currentPlan.getBillingPeriod(), BillingPeriod.ANNUAL);
 
             currentPhase = subscription.getCurrentPhase();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
index 157b8ee..56c1a74 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
@@ -33,7 +33,6 @@ public class TestUserApiChangePlanMemory extends TestUserApiChangePlan {
 
     @Test(enabled=true, groups={"fast"})
     public void testChangePlanBundleAlignEOTWithNoChargeThroughDate() {
-        System.err.println("STEPH THE TEST");
         invokeRealMethod(this);
     }
 
@@ -48,11 +47,6 @@ public class TestUserApiChangePlanMemory extends TestUserApiChangePlan {
     }
 
     @Test(enabled=true, groups={"fast"})
-    public void testChangePlanSubscriptionAlignEOTWithChargeThroughDate() {
-        invokeRealMethod(this);
-    }
-
-    @Test(enabled=true, groups={"fast"})
     public void testMultipleChangeLastIMM() {
         invokeRealMethod(this);
     }
@@ -62,16 +56,10 @@ public class TestUserApiChangePlanMemory extends TestUserApiChangePlan {
         invokeRealMethod(this);
     }
 
-    @Test(enabled=false, groups={"stress"})
-    public void stressTest() {
-        for (int i = 0; i < 20; i++) {
-            cleanupTest();
-            setupTest();
-            testMultipleChangeLastEOT();
-            cleanupTest();
-            setupTest();
-            testMultipleChangeLastIMM();
-        }
+    // STEPH set to false until we implement rescue example.
+    @Test(enabled=false, groups={"fast"})
+    public void testChangePlanChangePlanAlignEOTWithChargeThroughDate() {
+        invokeRealMethod(this);
     }
 
 }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
index 689dafa..5a5175a 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
@@ -69,17 +69,19 @@ public class TestUserApiChangePlanSql extends TestUserApiChangePlan {
     }
 
     @Test(enabled=true, groups={"sql"})
-    public void testChangePlanSubscriptionAlignEOTWithChargeThroughDate() {
+    public void testMultipleChangeLastIMM() {
         invokeRealMethod(this);
     }
 
     @Test(enabled=true, groups={"sql"})
-    public void testMultipleChangeLastIMM() {
+    public void testMultipleChangeLastEOT() {
         invokeRealMethod(this);
     }
 
-    @Test(enabled=true, groups={"sql"})
-    public void testMultipleChangeLastEOT() {
+    // STEPH rescue not implemented
+    @Test(enabled=false, groups={"sql"})
+    public void testChangePlanChangePlanAlignEOTWithChargeThroughDate() {
         invokeRealMethod(this);
     }
+
 }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
index 26fdcb0..44c126c 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
@@ -32,7 +32,7 @@ import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.IPlan;
 import com.ning.billing.catalog.api.IPlanPhase;
 import com.ning.billing.catalog.api.PhaseType;
-import com.ning.billing.catalog.api.PlanAlignment;
+import com.ning.billing.catalog.api.PlanAlignmentChange;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
 import com.ning.billing.entitlement.events.IEvent;
@@ -70,7 +70,6 @@ public abstract class TestUserApiCreate extends TestUserApiBase {
             assertNotNull(currentPlan);
             assertEquals(currentPlan.getProduct().getName(), productName);
             assertEquals(currentPlan.getProduct().getCategory(), ProductCategory.BASE);
-            assertEquals(currentPlan.getPlanAlignment(), PlanAlignment.START_OF_BUNDLE);
             assertEquals(currentPlan.getBillingPeriod(), BillingPeriod.MONTHLY);
 
             IPlanPhase currentPhase = subscription.getCurrentPhase();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
new file mode 100644
index 0000000..3fb58ee
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.entitlement.api.user;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Stage;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.IDuration;
+import com.ning.billing.catalog.api.IPlan;
+import com.ning.billing.catalog.api.IPlanPhase;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.glue.EngineModuleSqlMock;
+import com.ning.billing.util.clock.Clock;
+
+public class TestUserApiDemos extends TestUserApiBase {
+
+    @Override
+    protected Injector getInjector() {
+        return Guice.createInjector(Stage.DEVELOPMENT, new EngineModuleSqlMock());
+    }
+
+    /**
+     *  Initial demo for BP entitlement:
+     *  1. Create a Subscription
+     *  2. ChangePlan while in trial
+     *     -> Change is IMM
+     *     -> Trial is still 30 days long
+     *  3. Move through 2nd Phase
+     *  4. ChangePlan EOT
+     *     -> Show Change pending
+     *  5. Other ChangePlan EOT
+     *     -> Show it supercedes the first one
+     *  6. Move to EOT
+     *  7. Move to next Phase
+     *  8. Cancel EOT
+     */
+    @Test(enabled=true, groups="demos")
+    public void testDemo1() {
+
+        try {
+            System.out.println("DEMO 1 START");
+
+            /* STEP 1. CREATE SUBSCRIPTION */
+            Subscription subscription = createSubscription("Assault-Rifle", BillingPeriod.MONTHLY, "gunclubDiscount");
+            IPlanPhase trialPhase = subscription.getCurrentPhase();
+            assertEquals(trialPhase.getPhaseType(), PhaseType.TRIAL);
+
+            displayState(subscription.getId(), "STEP 1. CREATED SUBSCRIPTION");
+
+            /* STEP 2. CHANGE PLAN WHILE IN TRIAL */
+            testListener.pushExpectedEvent(NextEvent.CHANGE);
+            subscription.changePlan("Assault-Rifle", BillingPeriod.ANNUAL, "gunclubDiscount");
+            assertTrue(testListener.isCompleted(3000));
+
+            displayState(subscription.getId(), "STEP 2. CHANGED PLAN WHILE IN TRIAL");
+
+            /* STEP 3. MOVE TO DISCOUNT PHASE */
+            testListener.pushExpectedEvent(NextEvent.PHASE);
+            clock.setDeltaFromReality(trialPhase.getDuration(), DAY_IN_MS);
+            assertTrue(testListener.isCompleted(3000));
+
+            displayState(subscription.getId(), "STEP 3. MOVE TO DISCOUNT PHASE");
+
+            /* STEP 4. SET CTD AND CHANGE PLAN EOT */
+            List<IDuration> durationList = new ArrayList<IDuration>();
+            durationList.add(trialPhase.getDuration());
+            DateTime startDiscountPhase = Clock.addDuration(subscription.getStartDate(), durationList);
+
+            IDuration ctd = getDurationMonth(1);
+            DateTime newChargedThroughDate = Clock.addDuration(startDiscountPhase, ctd);
+            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate);
+            subscription = (Subscription) entitlementApi.getSubscriptionFromId(subscription.getId());
+
+            testListener.pushExpectedEvent(NextEvent.CHANGE);
+            subscription.changePlan("Shotgun", BillingPeriod.ANNUAL, "gunclubDiscount");
+            assertFalse(testListener.isCompleted(2000));
+            testListener.reset();
+
+            displayState(subscription.getId(), "STEP 4. SET CTD AND CHANGE PLAN EOT (Shotgun)");
+
+            /* STEP 5. CHANGE AGAIN */
+            testListener.pushExpectedEvent(NextEvent.CHANGE);
+            subscription.changePlan("Pistol", BillingPeriod.ANNUAL, "gunclubDiscount");
+            assertFalse(testListener.isCompleted(2000));
+            testListener.reset();
+
+            displayState(subscription.getId(), "STEP 5. CHANGE AGAIN EOT (Pistol)");
+
+            /* STEP 6. MOVE TO EOT AND CHECK CHANGE OCCURED */
+            testListener.pushExpectedEvent(NextEvent.CHANGE);
+            clock.addDeltaFromReality(ctd);
+            assertTrue(testListener.isCompleted(2000));
+
+            IPlan currentPlan = subscription.getCurrentPlan();
+            assertNotNull(currentPlan);
+            assertEquals(currentPlan.getProduct().getName(), "Pistol");
+            assertEquals(currentPlan.getProduct().getCategory(), ProductCategory.BASE);
+            assertEquals(currentPlan.getBillingPeriod(), BillingPeriod.ANNUAL);
+
+            IPlanPhase currentPhase = subscription.getCurrentPhase();
+            assertNotNull(currentPhase);
+            assertEquals(currentPhase.getPhaseType(), PhaseType.DISCOUNT);
+
+            displayState(subscription.getId(), "STEP 6. MOVE TO EOT");
+
+            /* STEP 7.  MOVE TO NEXT PHASE */
+            testListener.pushExpectedEvent(NextEvent.PHASE);
+            clock.addDeltaFromReality(currentPhase.getDuration());
+            assertTrue(testListener.isCompleted(3000));
+            subscription = (Subscription) entitlementApi.getSubscriptionFromId(subscription.getId());
+
+            currentPlan = subscription.getCurrentPlan();
+            assertNotNull(currentPlan);
+            assertEquals(currentPlan.getProduct().getName(), "Pistol");
+            assertEquals(currentPlan.getProduct().getCategory(), ProductCategory.BASE);
+            assertEquals(currentPlan.getBillingPeriod(), BillingPeriod.ANNUAL);
+
+            currentPhase = subscription.getCurrentPhase();
+            assertNotNull(currentPhase);
+            assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
+
+            displayState(subscription.getId(), "STEP 7.  MOVE TO NEXT PHASE");
+
+            /* STEP 8. CANCEL IMM (NO CTD) */
+            testListener.pushExpectedEvent(NextEvent.CANCEL);
+            subscription.cancel();
+
+            displayState(subscription.getId(), "STEP 8.  CANCELLATION");
+
+        } catch (EntitlementUserApiException e) {
+            Assert.fail(e.getMessage());
+        }
+
+    }
+
+
+    private void displayState(UUID subscriptionId, String stepMsg) {
+
+        System.out.println("");
+        System.out.println("******\t STEP " + stepMsg + " **************");
+
+        Subscription subscription = (Subscription) entitlementApi.getSubscriptionFromId(subscriptionId);
+
+
+        IPlan currentPlan = subscription.getCurrentPlan();
+        IPlanPhase currentPhase = subscription.getCurrentPhase();
+        String priceList = subscription.getCurrentPriceList();
+        System.out.println("");
+        System.out.println("\t CURRENT TIME = " + clock.getUTCNow());
+        System.out.println("");
+        System.out.println("\t CURRENT STATE = " +  subscription.getState());
+        System.out.println("\t CURRENT PRODUCT = " +  ((currentPlan == null) ? "NONE" : currentPlan.getProduct().getName()));
+        System.out.println("\t CURRENT TERM = " +  ((currentPlan == null) ? "NONE" : currentPlan.getBillingPeriod().toString()));
+        System.out.println("\t CURRENT PHASE = " +  ((currentPhase == null) ? "NONE" : currentPhase.getPhaseType()));
+        System.out.println("\t CURRENT PRICE LIST = " + ((priceList == null) ? "NONE" : priceList));
+        System.out.println("\t CURRENT \'SLUG\' = " +  ((currentPhase == null) ? "NONE" : currentPhase.getName()));
+
+        System.out.println("");
+
+    }
+
+    @Test(enabled= true, groups={"stress"})
+    public void stressTest() {
+        for (int i = 0; i < 100; i++) {
+            cleanupTest();
+            setupTest();
+            testDemo1();
+        }
+    }
+}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/ApiEventProcessorMemoryMock.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/ApiEventProcessorMemoryMock.java
index 2c35a8e..4089936 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/ApiEventProcessorMemoryMock.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/core/ApiEventProcessorMemoryMock.java
@@ -21,14 +21,14 @@ import java.util.List;
 import com.google.inject.Inject;
 import com.ning.billing.entitlement.engine.dao.IEntitlementDao;
 import com.ning.billing.entitlement.events.IEvent;
-import com.ning.billing.entitlement.glue.IEngineConfig;
+import com.ning.billing.entitlement.glue.IEntitlementConfig;
 import com.ning.billing.util.clock.IClock;
 
 public class ApiEventProcessorMemoryMock extends ApiEventProcessorBase {
 
 
     @Inject
-    public ApiEventProcessorMemoryMock(IClock clock, IEntitlementDao dao, IEngineConfig config) {
+    public ApiEventProcessorMemoryMock(IClock clock, IEntitlementDao dao, IEntitlementConfig config) {
         super(clock, dao, config);
     }
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/EntitlementDaoMemoryMock.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/EntitlementDaoMemoryMock.java
index 45754d0..143b069 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/EntitlementDaoMemoryMock.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/EntitlementDaoMemoryMock.java
@@ -42,7 +42,7 @@ import com.ning.billing.entitlement.events.phase.IPhaseEvent;
 import com.ning.billing.entitlement.events.phase.PhaseEvent;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 import com.ning.billing.entitlement.events.user.IUserEvent;
-import com.ning.billing.entitlement.glue.IEngineConfig;
+import com.ning.billing.entitlement.glue.IEntitlementConfig;
 import com.ning.billing.util.clock.IClock;
 
 public class EntitlementDaoMemoryMock implements IEntitlementDao, IEntitlementDaoMock {
@@ -53,10 +53,10 @@ public class EntitlementDaoMemoryMock implements IEntitlementDao, IEntitlementDa
     private final List<ISubscription> subscriptions;
     private final TreeSet<IEvent> events;
     private final IClock clock;
-    private final IEngineConfig config;
+    private final IEntitlementConfig config;
 
     @Inject
-    public EntitlementDaoMemoryMock(IClock clock, IEngineConfig config) {
+    public EntitlementDaoMemoryMock(IClock clock, IEntitlementConfig config) {
         super();
         this.clock = clock;
         this.config = config;
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/EntitlementDaoSqlMock.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/EntitlementDaoSqlMock.java
index 0814059..114021e 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/EntitlementDaoSqlMock.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/EntitlementDaoSqlMock.java
@@ -24,7 +24,7 @@ import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 
 import com.google.inject.Inject;
-import com.ning.billing.entitlement.glue.IEngineConfig;
+import com.ning.billing.entitlement.glue.IEntitlementConfig;
 import com.ning.billing.util.clock.IClock;
 
 public class EntitlementDaoSqlMock extends EntitlementDao implements IEntitlementDaoMock {
@@ -32,7 +32,7 @@ public class EntitlementDaoSqlMock extends EntitlementDao implements IEntitlemen
     private final ResetSqlDao resetDao;
 
     @Inject
-    public EntitlementDaoSqlMock(DBI dbi, IClock clock, IEngineConfig config) {
+    public EntitlementDaoSqlMock(DBI dbi, IClock clock, IEntitlementConfig config) {
         super(dbi, clock, config);
         this.resetDao = dbi.onDemand(ResetSqlDao.class);
     }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/TestEntitlementDao.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/TestEntitlementDao.java
index 0694fac..cd6da83 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/TestEntitlementDao.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/TestEntitlementDao.java
@@ -61,7 +61,7 @@ public class TestEntitlementDao extends TestUserApiBase {
 
         DateTime now = new DateTime();
         IPlan plan = catalog.getPlan(productName, term, planSetName);
-        IEvent event = new ApiEventCreate(UUID.randomUUID(), now, now, plan,planSetName, now, now, 1);
+        IEvent event = new ApiEventCreate(UUID.randomUUID(), now, now, plan.getName(), "evergreen", planSetName, now, now, 1);
         dao.insertEvent(event);
 
         sleep();
@@ -105,7 +105,7 @@ public class TestEntitlementDao extends TestUserApiBase {
         String planSetName = "standard";
 
         IPlan plan = catalog.getPlan(productName, term, planSetName);
-        final IEvent event = new ApiEventCreate(UUID.randomUUID(), now, now, plan, planSetName, now, now, 1);
+        final IEvent event = new ApiEventCreate(UUID.randomUUID(), now, now, plan.getName(), "evergreen", planSetName, now, now, 1);
 
         dao.inTransaction(new Transaction<Void, ISubscriptionSqlDao>() {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/EngineModuleMemoryMock.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/EngineModuleMemoryMock.java
index 0f422f1..70120e7 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/EngineModuleMemoryMock.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/EngineModuleMemoryMock.java
@@ -21,13 +21,13 @@ import com.ning.billing.entitlement.engine.core.ApiEventProcessorMemoryMock;
 import com.ning.billing.entitlement.engine.core.IApiEventProcessor;
 import com.ning.billing.entitlement.engine.dao.EntitlementDaoMemoryMock;
 import com.ning.billing.entitlement.engine.dao.IEntitlementDao;
-import com.ning.billing.entitlement.glue.EngineModule;
+import com.ning.billing.entitlement.glue.EntitlementModule;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.clock.IClock;
 
 
-public class EngineModuleMemoryMock extends EngineModule {
+public class EngineModuleMemoryMock extends EntitlementModule {
     @Override
     protected void installApiEventProcessor() {
         bind(IApiEventProcessor.class).to(ApiEventProcessorMemoryMock.class).asEagerSingleton();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/EngineModuleSqlMock.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/EngineModuleSqlMock.java
index 3e8a0b4..214ab3e 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/EngineModuleSqlMock.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/EngineModuleSqlMock.java
@@ -21,7 +21,7 @@ import com.ning.billing.entitlement.engine.dao.IEntitlementDao;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.clock.IClock;
 
-public class EngineModuleSqlMock extends EngineModule {
+public class EngineModuleSqlMock extends EntitlementModule {
 
     @Override
     protected void installEntitlementDao() {
diff --git a/entitlement/src/test/resources/log4j.xml b/entitlement/src/test/resources/log4j.xml
index 4f9885b..75abc76 100644
--- a/entitlement/src/test/resources/log4j.xml
+++ b/entitlement/src/test/resources/log4j.xml
@@ -26,7 +26,7 @@
 
 
     <logger name="com.ning.billing.entitlement">
-        <level value="debug"/>
+        <level value="info"/>
     </logger>
 
     <root>
diff --git a/entitlement/src/test/resources/testInput.xml b/entitlement/src/test/resources/testInput.xml
index 7ba09ed..59b9093 100644
--- a/entitlement/src/test/resources/testInput.xml
+++ b/entitlement/src/test/resources/testInput.xml
@@ -40,6 +40,7 @@ Use Cases to do:
 	xsi:noNamespaceSchemaLocation="../../main/resources/CatalogSchema.xsd ">
 
 	<effectiveDate>2011-10-08T00:00:00+00:00</effectiveDate>
+	<catalogName>Firearms</catalogName>
 
 	<currencies>
 		<currency>USD</currency>
@@ -47,14 +48,8 @@ Use Cases to do:
 		<currency>GBP</currency>
 	</currencies>
 	
-	<productTypes>
-		<productType name="Firearms" />
-		<productType name="Blade" />
-	</productTypes>
-
 	<products>
 		<product name="Pistol">
-			<type>Firearms</type>
 			<category>BASE</category>
 			<available>
 				<addonProduct>Telescopic-Scope</addonProduct>
@@ -62,11 +57,9 @@ Use Cases to do:
 			</available>
 		</product>
 		<product name="Shotgun">
-			<type>Firearms</type>
 			<category>BASE</category>
 		</product>
 		<product name="Assault-Rifle">
-			<type>Firearms</type>
 			<category>BASE</category>
 			<included> 
 				<addonProduct>Telescopic-Scope</addonProduct>
@@ -76,31 +69,24 @@ Use Cases to do:
 			</available>
 		</product>
 		<product name="Telescopic-Scope">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 		<product name="Laser-Scope">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 		<product name="Holster">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 		<product name="Extra-Ammo">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 		<product name="Refurbish-Maintenance">
-			<type>Firearms</type>
 			<category>ADD_ON</category>
 		</product>
 		<product name="Bowie-Knife">
-			<type>Blade</type>
 			<category>BASE</category>
 		</product>
 		<product name="Samuri-Sword">
-			<type>Blade</type>
 			<category>BASE</category>
 		</product>
 	</products>
@@ -113,39 +99,65 @@ Use Cases to do:
 				<product>Assault-Rifle</product>
 			</tier>
 		</tiers>
-		<changeRule>
+		<changePolicyRule>
 			<qualifier>DEFAULT</qualifier>
 			<policy>END_OF_TERM</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>TERM_FROM_SHORT_TO_LONG</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeRule>
+		</changePolicyRule>
+		<changePolicyRule>
 			<qualifier>PRODUCT_FROM_LOW_TO_HIGH</qualifier>
 			<policy>IMMEDIATE</policy>
-		</changeRule>
-		<changeCase> 
+		</changePolicyRule>
+		<changePolicyCase> 
 			<fromBillingPeriod>MONTHLY</fromBillingPeriod>
 			<toProduct>Assault-Rifle</toProduct>
 			<toBillingPeriod>MONTHLY</toBillingPeriod>
 			<policy>END_OF_TERM</policy>
-		</changeCase>
-		<changeCase> 
+		</changePolicyCase>
+		<changePolicyCase> 
 			<toPriceList>rescue</toPriceList>
 			<policy>END_OF_TERM</policy>
-		</changeCase>		
-		<changeCase> 
+		</changePolicyCase>		
+		<changePolicyCase> 
 			<phaseType>TRIAL</phaseType>
 			<policy>IMMEDIATE</policy>
-		</changeCase>
-		<cancelCase>
+		</changePolicyCase>
+		<changeAlignmentCase>
+			<alignment>START_OF_SUBSCRIPTION</alignment>
+		</changeAlignmentCase>
+		<changeAlignmentCase>
+			<toPriceList>rescue</toPriceList>
+			<alignment>CHANGE_OF_PLAN</alignment>
+		</changeAlignmentCase>
+		<changeAlignmentCase>
+			<fromPriceList>rescue</fromPriceList>
+			<toPriceList>rescue</toPriceList>
+			<alignment>CHANGE_OF_PRICELIST</alignment>
+		</changeAlignmentCase>
+		<cancelPolicyCase>
 			<policy>END_OF_TERM</policy>
-		</cancelCase>
-		<cancelCase>
+		</cancelPolicyCase>
+		<cancelPolicyCase>
 			<phaseType>TRIAL</phaseType>
 			<policy>IMMEDIATE</policy>
-		</cancelCase>
+		</cancelPolicyCase>
+		<createAlignmentCase>
+			<alignment>START_OF_BUNDLE</alignment>
+		</createAlignmentCase>
+		<billingAlignmentCase>
+			<alignment>ACCOUNT</alignment>
+		</billingAlignmentCase>
+		<billingAlignmentCase>
+			<billingPeriod>ANNUAL</billingPeriod>
+			<alignment>SUBSCRIPTION</alignment>
+		</billingAlignmentCase>
+		<billingAlignmentCase>
+			<productCategory>ADD_ON</productCategory>
+			<alignment>BUNDLE</alignment>
+		</billingAlignmentCase>
 	</rules>
 
 	<plans>
@@ -172,8 +184,6 @@ Use Cases to do:
 					<price><currency>USD</currency><value>29.95</value></price>								
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="shotgun-monthly">
 			<product>Shotgun</product>
@@ -199,8 +209,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>169.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="assault-rifle-monthly">
 			<product>Assault-Rifle</product>
@@ -225,8 +233,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>399.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>ACCOUNT</billingAlignment>
 		</plan>
 		<plan name="pistol-annual">
 			<product>Pistol</product>
@@ -251,8 +257,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>199.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="shotgun-annual">
 			<product>Shotgun</product>
@@ -277,8 +281,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>1699.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="assault-rifle-annual">
 			<product>Assault-Rifle</product>
@@ -303,8 +305,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>3999.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="pistol-annual-gunclub-discount">
 			<product>Pistol</product>
@@ -341,8 +341,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>199.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="shotgun-annual-gunclub-discount">
 			<product>Shotgun</product>
@@ -379,8 +377,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>1699.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="assault-rifle-annual-gunclub-discount">
 			<product>Assault-Rifle</product>
@@ -417,8 +413,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>3999.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="laser-scope-monthly">
 		<product>Laser-Scope</product>
@@ -433,8 +427,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>1999.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>BUNDLE</billingAlignment>
 		</plan>
 		<plan name="telescopic-scope-monthly">
 			<product>Telescopic-Scope</product>
@@ -449,8 +441,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>999.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>BUNDLE</billingAlignment>
 		</plan>
 		<plan name="extra-ammo-monthly">
 			<product>Extra-Ammo</product>
@@ -465,8 +455,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>999.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>BUNDLE</billingAlignment>
 			<plansAllowedInBundle>-1</plansAllowedInBundle> <!-- arbitrary number of these (multipack) -->
 		</plan>
 		<plan name="holster-monthly-regular">
@@ -492,8 +480,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>199.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_BUNDLE</planAlignment>
-			<billingAlignment>BUNDLE</billingAlignment>
 		</plan>
 		<plan name="holster-monthly-special">
 			<product>Holster</product>
@@ -518,8 +504,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>199.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_SUBSCRIPTION</planAlignment>
-			<billingAlignment>BUNDLE</billingAlignment>
 		</plan>
 		<plan name="assault-rifle-annual-rescue">
 			<product>Assault-Rifle</product>
@@ -548,8 +532,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>3999.95</value></price>
 				</recurringPrice>
 			</finalPhase>
-			<planAlignment>START_OF_SUBSCRIPTION</planAlignment>
-			<billingAlignment>SUBSCRIPTION</billingAlignment>
 		</plan>
 		<plan name="refurbish-maintenance">
 			<product>Refurbish-Maintenance</product>
@@ -570,8 +552,6 @@ Use Cases to do:
 					<price><currency>GBP</currency><value>599.95</value></price>
 				</fixedPrice>
 			</finalPhase>
-			<planAlignment>START_OF_SUBSCRIPTION</planAlignment>
-			<billingAlignment>BUNDLE</billingAlignment>
 		</plan>
 	</plans>
 	<priceLists>

pom.xml 4(+2 -2)

diff --git a/pom.xml b/pom.xml
index 23f4a7e..a6d4be2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -121,8 +121,8 @@
             </dependency>
             <dependency>
                 <groupId>com.ning.jetty</groupId>
-                <artifactId>ning-service-skeleton-core</artifactId>
-                <version>0.0.2</version>
+                <artifactId>ning-service-skeleton-utils</artifactId>
+                <version>0.0.6-SNAPSHOT</version>
             </dependency>
             <dependency>
                 <groupId>commons-io</groupId>