001: /*
002: * Created on Oct 20, 2003
003: */
004: package org.openedit.store.xmldb;
005:
006: import java.io.FileNotFoundException;
007: import java.util.HashMap;
008: import java.util.Iterator;
009: import java.util.Map;
010:
011: import org.apache.commons.logging.Log;
012: import org.apache.commons.logging.LogFactory;
013: import org.dom4j.DocumentException;
014: import org.dom4j.Element;
015: import org.openedit.money.Fraction;
016: import org.openedit.money.Money;
017: import org.openedit.store.CreditCardType;
018: import org.openedit.store.HandlingCharge;
019: import org.openedit.store.ProductPathFinder;
020: import org.openedit.store.Store;
021: import org.openedit.store.StoreException;
022: import org.openedit.store.products.SegmentedProductPathFinder;
023: import org.openedit.store.shipping.BaseShippingMethod;
024: import org.openedit.store.shipping.PriceBasedShippingMethod;
025: import org.openedit.store.shipping.WeightBasedShippingMethod;
026:
027: import com.openedit.ModuleManager;
028: import com.openedit.OpenEditException;
029: import com.openedit.WebPageRequest;
030: import com.openedit.config.XMLConfiguration;
031: import com.openedit.page.Page;
032: import com.openedit.page.manage.PageManager;
033: import com.openedit.util.XmlUtil;
034:
035: /**
036: * Creates and sets up our store object.
037: * This class is responsible for configuring all the other objects we need
038: * @author cburkey
039: *
040: */
041: public class XmlStoreArchive {
042: private static final Log log = LogFactory
043: .getLog(XmlStoreArchive.class);
044:
045: protected ModuleManager fieldModuleManager;
046: protected PageManager fieldPageManager;
047: protected Map fieldStores;
048: protected String fieldBeanName = "store";
049:
050: public boolean hasChanged(Store inStore) throws OpenEditException {
051: Page config = getPageManager().getPage(
052: inStore.getStoreHome() + "/configuration/store.xml");
053: if (config.getLastModified().getTime() == inStore
054: .getLastModified()) {
055: return false;
056: } else {
057: return true;
058: }
059: }
060:
061: public Store loadStore(WebPageRequest inReq) throws StoreException {
062: Store store = (Store) inReq.getPageValue("store");
063: if (store == null) {
064: store = getStore(inReq.getContentPage());
065: //inReq.putSessionValue("store", store); //Should not use session values if not needed
066: inReq.putPageValue("store", store);
067: }
068: inReq.putPageValue("catalogid", store.getCatalogId());
069: return store;
070: }
071:
072: public Store getStore(Page inPage) throws StoreException {
073: String name = inPage.get("catalogid");
074: if (name == null) {
075: name = "store";
076: log
077: .error("Should define catalogid property. Defaulting to /store/");
078: }
079: return getStore(name);
080: }
081:
082: public Store getStore(String inCatalogId) throws StoreException {
083: try {
084: Store store = getStoreForCatalog(inCatalogId);
085: if (hasChanged(store)) {
086: store.clear();
087: configureStore(store, inCatalogId);
088: }
089: return store;
090: } catch (Exception ex) {
091: throw new StoreException(ex);
092: }
093: }
094:
095: /**
096: * @param storeFile
097: * @throws StoreException
098: * @throws FileNotFoundException
099: * @throws DocumentException
100: * @throws Exception
101: */
102: protected void configureStore(Store inStore, String inCatalogId)
103: throws StoreException, FileNotFoundException,
104: DocumentException, Exception {
105: log.info("Configuring " + inCatalogId);
106: Page config = getPageManager().getPage(
107: "/" + inCatalogId + "/configuration/store.xml");
108: inStore.setLastModified(config.getLastModified().getTime());
109: inStore.getProductArchive().clearProducts();
110:
111: Element rootElement = new XmlUtil().getXml(config.getReader(),
112: config.getCharacterEncoding());
113:
114: inStore.setConfiguration(new XMLConfiguration(rootElement));
115: //configureOrderArchive(rootElement);
116: String hostName = rootElement.elementTextTrim("hostName");
117: if (hostName == null) {
118: //legacy support
119: hostName = rootElement.elementTextTrim("hostname");
120: }
121: inStore.setHostName(hostName);
122: inStore.setName(rootElement.elementTextTrim("name"));
123: Element coup = rootElement.element("coupons");
124: inStore.setCouponsAccepted(coup != null
125: && "true".equals(coup.attributeValue("enabled")));
126:
127: Element ponum = rootElement.element("ponumber");
128: inStore.setCouponsAccepted(coup != null
129: && "true".equals(coup.attributeValue("enabled")));
130:
131: inStore.setSmtpServer(rootElement
132: .elementTextTrim("smtp-server"));
133: for (Iterator it = rootElement.elementIterator("to-address"); it
134: .hasNext();) {
135: Element toAddressElement = (Element) it.next();
136: inStore.addToAddress(toAddressElement.getTextTrim());
137: }
138: for (Iterator it = rootElement
139: .elementIterator("notify-address"); it.hasNext();) {
140: Element toAddressElement = (Element) it.next();
141: inStore.addNotifyAddress(toAddressElement.getTextTrim());
142: }
143: inStore.setFromAddress(rootElement
144: .elementTextTrim("from-address"));
145: inStore.setEmailLayout(rootElement
146: .elementTextTrim("email-layout"));
147: inStore.setOrderLayout(rootElement
148: .elementTextTrim("order-layout"));
149: inStore.setUsesPoNumbers(Boolean.parseBoolean(rootElement
150: .elementTextTrim("uses-po-numbers")));
151: inStore.setDisplayTermsConditions(Boolean
152: .parseBoolean(rootElement
153: .elementTextTrim("display-terms-conditions")));
154: inStore.setUsesBillMeLater(Boolean.parseBoolean(rootElement
155: .elementTextTrim("uses-bill-me-later")));
156: inStore.setAllowDuplicateAccounts(Boolean
157: .parseBoolean(rootElement
158: .elementTextTrim("allow-duplicate-accounts")));
159: inStore.setAllowSpecialRequest(Boolean.parseBoolean(rootElement
160: .elementTextTrim("allow-special-request")));
161: inStore.setAutoCapture(Boolean.parseBoolean(rootElement
162: .elementTextTrim("auto-capture-credit-cards")));
163:
164: configureCreditCards(inStore, rootElement);
165: configureTax(inStore, rootElement);
166: //Load up the search capability
167:
168: configureShipping(inStore, rootElement);
169: configureProductPathFinder(inStore, rootElement);
170: inStore.getFieldArchive().setConfigurationPath(
171: "/" + inStore.getCatalogId() + "/configuration/");
172: inStore.getOrderSearch().setFieldArchive(
173: inStore.getFieldArchive());
174: }
175:
176: /**
177: * @param document
178: * @throws StoreException
179: */
180: private void configureShipping(Store inStore, Element rootElement)
181: throws StoreException {
182: //this is if the user has not selected one and there is only one choice
183: //this api can probably be deleted?
184: Element assignShippingMethodElem = rootElement
185: .element("assign-shipping-method");
186: if (assignShippingMethodElem != null) {
187: inStore.setAssignShippingMethod(Boolean.valueOf(
188: assignShippingMethodElem.getTextTrim())
189: .booleanValue());
190: } else {
191: inStore.setAssignShippingMethod(false);
192: }
193:
194: inStore.getAllShippingMethods().clear();
195:
196: Iterator methods = rootElement
197: .elementIterator("price-shipping-method");
198: if (!methods.hasNext()) {
199: //try the old name
200: methods = rootElement.elementIterator("shipping-method");
201: }
202: for (; methods.hasNext();) {
203: Element method = (Element) methods.next();
204: PriceBasedShippingMethod shippingmethod = (PriceBasedShippingMethod) getModuleManager()
205: .getBean("priceBasedShipping");
206: configureShippingMethod(shippingmethod, method);
207:
208: appendHandlingCharge(shippingmethod, method);
209:
210: inStore.getAllShippingMethods().add(shippingmethod);
211: }
212:
213: for (Iterator iter = rootElement
214: .elementIterator("weight-shipping-method"); iter
215: .hasNext();) {
216: Element element = (Element) iter.next();
217: WeightBasedShippingMethod shippingmethod = (WeightBasedShippingMethod) getModuleManager()
218: .getBean("weightBasedShipping");
219: configureShippingMethod(shippingmethod, element);
220:
221: appendHandlingCharge(shippingmethod, element);
222:
223: inStore.getAllShippingMethods().add(shippingmethod);
224: }
225: }
226:
227: private void configureShippingMethod(
228: BaseShippingMethod shippingmethod, Element method) {
229: shippingmethod.setDescription(method
230: .attributeValue("description"));
231: shippingmethod.setId(method.attributeValue("id"));
232: String costStr = method.attributeValue("costs");
233: if (costStr != null) {
234: Money cost = new Money(costStr);
235: shippingmethod.setCost(cost);
236: }
237: String percentageCostStr = method
238: .attributeValue("percentageCosts");
239: if (percentageCostStr != null) {
240: shippingmethod.setPercentageCost(Double
241: .parseDouble(percentageCostStr));
242: }
243: String lowerThresholdStr = method
244: .attributeValue("lowerThreshold");
245: if (lowerThresholdStr != null) {
246: shippingmethod.setLowerThreshold(new Money(
247: lowerThresholdStr));
248: }
249: String upperThresholdStr = method
250: .attributeValue("upperThreshold");
251: if (upperThresholdStr != null) {
252: shippingmethod.setUpperThreshold(new Money(
253: upperThresholdStr));
254: }
255: String hidden = method.attributeValue("hidden");
256: shippingmethod.setHidden(Boolean.parseBoolean(hidden));
257: }
258:
259: private void appendHandlingCharge(
260: BaseShippingMethod shippingmethod, Element method) {
261: for (Iterator handlingCharges = method
262: .elementIterator("handling-charge"); handlingCharges
263: .hasNext();) {
264: Element handlingChargeElem = (Element) handlingCharges
265: .next();
266: HandlingCharge handlingCharge = new HandlingCharge();
267: handlingCharge.setLevel(handlingChargeElem
268: .attributeValue("level"));
269: String cost = handlingChargeElem.attributeValue("costs");
270: if (cost != null) {
271: handlingCharge.setCost(new Money(cost));
272: } else {
273: handlingCharge.setCost(Money.ZERO);
274: }
275: String additionalCosts = handlingChargeElem
276: .attributeValue("additionalCosts");
277: if (additionalCosts != null) {
278: handlingCharge.setAdditionalCosts(additionalCosts
279: .equalsIgnoreCase("true"));
280: }
281: shippingmethod.addHandlingCharge(handlingCharge);
282: }
283: }
284:
285: /**
286: * @throws StoreException
287:
288: private void configureSearch() throws StoreException
289: {
290: getProductSearch().setSearchDirectory(new File(getStore().getStoreDirectory(), PRODUCTS_DIR));
291: getStore().setStoreSearcher(getProductSearch());
292: getStore().getCustomerArchive().setCustomersDirectory(new File( getStore().getStoreDirectory().getParentFile(),"WEB-INF/users/"));
293: }
294: */
295:
296: /**
297: * @param inElement
298: */
299: private void configureTax(Store inStore, Element inElement) {
300: for (Iterator iter = inElement.elementIterator("tax"); iter
301: .hasNext();) {
302: Element element = (Element) iter.next();
303: String state = element.attributeValue("statecode");
304: Fraction rate = new Fraction(element.attributeValue("rate"));
305: inStore.putTaxRate(state, rate);
306: }
307: }
308:
309: /**
310: * @param inElement
311: */
312: private void configureCreditCards(Store inStore, Element inElement) {
313: for (Iterator iter = inElement
314: .elementIterator("credit-card-type"); iter.hasNext();) {
315: Element element = (Element) iter.next();
316:
317: CreditCardType type = new CreditCardType(element
318: .attributeValue("name"));
319: type.setId(element.attributeValue("id"));
320:
321: inStore.addCreditCardType(type);
322: }
323: }
324:
325: /**
326: * Sets the {@link ProductPathFinder} on the store from the
327: * <tt><default-product-paths></tt> or the
328: * <tt><segmented-product-paths></tt> elements within the given root
329: * element.
330: *
331: * @param inRootElement The store root element
332: */
333: private void configureProductPathFinder(Store inStore,
334: Element inRootElement) throws StoreException {
335: SegmentedProductPathFinder pathFinder = new SegmentedProductPathFinder();
336: Element element = inRootElement
337: .element("segmented-product-paths");
338: if (element != null) {
339: Element segmentLengthElem = element
340: .element("segment-length");
341: if (segmentLengthElem != null) {
342: pathFinder.setSegmentLength(Integer
343: .parseInt(segmentLengthElem.getTextTrim()));
344: }
345: Element reverse = element.element("reverse");
346: if (reverse != null) {
347: pathFinder.setReverse(Boolean.parseBoolean(reverse
348: .getTextTrim()));
349: }
350: Element group = element.element("groupincategory");
351: if (group != null) {
352: pathFinder.setGroupInTopCategory(Boolean
353: .parseBoolean(group.getTextTrim()));
354: }
355: }
356: inStore.setProductPathFinder(pathFinder);
357: }
358:
359: public PageManager getPageManager() {
360: return fieldPageManager;
361: }
362:
363: public void setPageManager(PageManager inPageManager) {
364: fieldPageManager = inPageManager;
365: }
366:
367: public ModuleManager getModuleManager() {
368: return fieldModuleManager;
369: }
370:
371: public void setModuleManager(ModuleManager inModuleManager) {
372: fieldModuleManager = inModuleManager;
373: }
374:
375: public Map getStores() {
376: if (fieldStores == null) {
377: fieldStores = new HashMap();
378: }
379: return fieldStores;
380: }
381:
382: public Store getStoreForCatalog(String inCatalogId)
383: throws Exception {
384: Store store = (Store) getStores().get(inCatalogId);
385: if (store == null) {
386: store = (Store) getModuleManager().getBean(getBeanName()); //singleton=false
387: store.setCatalogId(inCatalogId);
388: configureStore(store, inCatalogId);
389:
390: getStores().put(inCatalogId, store);
391: }
392: return store;
393:
394: }
395:
396: public String getBeanName() {
397: return fieldBeanName;
398: }
399:
400: public void setBeanName(String inBeanName) {
401: fieldBeanName = inBeanName;
402: }
403:
404: }
|