|
From: Leon T. <le...@gr...> - 2007-01-10 00:41:45
|
Author: leon Date: 2007-01-09 16:41:43 -0800 (Tue, 09 Jan 2007) New Revision: 41 Added: versions/0.9/trunk/entitydef/entitygroup.xml versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java Removed: versions/0.9/trunk/entitydef/entitygroup_customer.xml Modified: versions/0.9/trunk/ofbiz-component.xml versions/0.9/trunk/servicedef/services.xml Log: Service and intermediate entity for importing products. Also merge the entitygroup.xml files into one. Copied: versions/0.9/trunk/entitydef/entitygroup.xml (from rev 35, versions/0.9/trunk/entitydef/entitygroup_customer.xml) =================================================================== --- versions/0.9/trunk/entitydef/entitygroup_customer.xml 2007-01-09 18:28:47 UTC (rev 35) +++ versions/0.9/trunk/entitydef/entitygroup.xml 2007-01-10 00:41:43 UTC (rev 41) @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * Copyright (c) 2006 - 2007 Open Source Strategies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Honest Public License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Honest Public License for more details. + * + * You should have received a copy of the Honest Public License + * along with this program; if not, write to Funambol, + * Foundation, Inc., 51 Frankli +n St, Fifth Floor, Boston, MA 02110-1301 USA +--> + +<entitygroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/entitygroup.xsd"> + + <!-- =================================== --> + <!-- org.opentaps.dataimport.customers --> + <!-- =================================== --> + + <entity-group group="org.ofbiz" entity="DataImportCustomer"/> + + <!-- =================================== --> + <!-- org.opentaps.dataimport.products --> + <!-- =================================== --> + + <entity-group group="org.ofbiz" entity="DataImportProduct"/> + +</entitygroup> Deleted: versions/0.9/trunk/entitydef/entitygroup_customer.xml =================================================================== --- versions/0.9/trunk/entitydef/entitygroup_customer.xml 2007-01-10 00:37:49 UTC (rev 40) +++ versions/0.9/trunk/entitydef/entitygroup_customer.xml 2007-01-10 00:41:43 UTC (rev 41) @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - * Copyright (c) 2006 - 2007 Open Source Strategies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the Honest Public License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Honest Public License for more details. - * - * You should have received a copy of the Honest Public License - * along with this program; if not, write to Funambol, - * Foundation, Inc., 51 Frankli -n St, Fifth Floor, Boston, MA 02110-1301 USA ---> - -<!-- TODO: merge into entitygroup.xml --> -<entitygroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/entitygroup.xsd"> - - <!-- =================================== --> - <!-- org.opentaps.dataimport.customers --> - <!-- =================================== --> - - <entity-group group="org.ofbiz" entity="DataImportCustomer"/> - -</entitygroup> Modified: versions/0.9/trunk/ofbiz-component.xml =================================================================== --- versions/0.9/trunk/ofbiz-component.xml 2007-01-10 00:37:49 UTC (rev 40) +++ versions/0.9/trunk/ofbiz-component.xml 2007-01-10 00:41:43 UTC (rev 41) @@ -25,7 +25,8 @@ <!-- these entities are to help importing data and can be removed if not needed --> <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel_customer.xml"/> - <entity-resource type="group" reader-name="main" loader="main" location="entitydef/entitygroup_customer.xml"/> + <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel_product.xml"/> + <entity-resource type="group" reader-name="main" loader="main" location="entitydef/entitygroup.xml"/> <entity-resource type="data" reader-name="demo" loader="main" location="data/DemoImportCustomers.xml"/> Modified: versions/0.9/trunk/servicedef/services.xml =================================================================== --- versions/0.9/trunk/servicedef/services.xml 2007-01-10 00:37:49 UTC (rev 40) +++ versions/0.9/trunk/servicedef/services.xml 2007-01-10 00:41:43 UTC (rev 41) @@ -38,4 +38,17 @@ <attribute type="Integer" mode="OUT" name="customersImported" optional="true"/> </service> + <service name="importProducts" engine="java" use-transaction="false" + location="org.opentaps.dataimport.ProductImportServices" invoke="importProducts"> + <description> + Import products using DataImportProduct. + Note that this service is not wrapped in a transaction. Each customer record imported is in its + own transaction, so it can store as many good records as possible. + The goodIdentificationTypeIdN parameters correspond to the type of the customIdN fields in DataImportProduct. + </description> + <attribute type="String" mode="IN" name="goodIdentificationTypeId1" optional="false"/> + <attribute type="String" mode="IN" name="goodIdentificationTypeId2" optional="false"/> + <attribute type="Integer" mode="OUT" name="productsImported" optional="true"/> + </service> + </services> Added: versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java =================================================================== --- versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-10 00:37:49 UTC (rev 40) +++ versions/0.9/trunk/src/org/opentaps/dataimport/ProductImportServices.java 2007-01-10 00:41:43 UTC (rev 41) @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2006 - 2007 Open Source Strategies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Honest Public License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Honest Public License for more details. + * + * You should have received a copy of the Honest Public License + * along with this program; if not, write to Funambol, + * 643 Bair Island Road, Suite 305 - Redwood City, CA 94063, USA + */ + +package org.opentaps.dataimport; + +import java.util.*; +import java.sql.Timestamp; +import java.math.BigDecimal; + +import javolution.util.FastList; +import javolution.util.FastMap; + +import org.ofbiz.entity.GenericDelegator; +import org.ofbiz.base.util.*; +import org.ofbiz.entity.*; +import org.ofbiz.entity.condition.*; +import org.ofbiz.entity.util.*; +import org.ofbiz.entity.transaction.TransactionUtil; +import org.ofbiz.service.ServiceUtil; +import org.ofbiz.service.DispatchContext; + +/** + * Import products via intermediate DataImportProduct entity. + * + * @author <a href="mailto:le...@op...">Leon Torres</a> + */ +public class ProductImportServices { + + public static String module = ProductImportServices.class.getName(); + + public static Map importProducts(DispatchContext dctx, Map context) { + GenericDelegator delegator = dctx.getDelegator(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + + String goodIdentificationTypeId1 = (String) context.get("goodIdentificationTypeId1"); + String goodIdentificationTypeId2 = (String) context.get("goodIdentificationTypeId2"); + Timestamp now = UtilDateTime.nowTimestamp(); + + int imported = 0; + + // main try/catch block that traps errors related to obtaining data from delegator + try { + // need to get an ELI because of possibly large number of records. productId <> null will get all records + EntityConditionList conditions = new EntityConditionList( UtilMisc.toList( + new EntityExpr("productId", EntityOperator.NOT_EQUAL, null), + new EntityExpr("processedTimestamp", EntityOperator.EQUALS, null) // leave out previously processed products + ), EntityOperator.AND); + TransactionUtil.begin(); // since the service is not inside a transaction, this needs to be in its own transaction, or you'll get a harmless exception + EntityListIterator importProducts = delegator.findListIteratorByCondition("DataImportProduct", conditions, null, null); + TransactionUtil.commit(); + + GenericValue product = null; + while ((product = (GenericValue) importProducts.next()) != null) { + + try { + // use the helper method to decode the product into a List of GenericValues + List toStore = decodeProduct(product, now, goodIdentificationTypeId1, goodIdentificationTypeId2, delegator); + if (toStore == null) { + Debug.logWarning("Faild to import product["+product.get("productId")+"] because data was bad. Check preceding warnings for reason.", module); + } + + // next we're going to store all each product's data in its own transaction, so if one product's data is bad, the others will still get stored + TransactionUtil.begin(); + + // store the results and mark this product as processed + delegator.storeAll(toStore); + + // log the import + Debug.logInfo("Successfully imported product ["+product.get("productId")+"].", module); + imported += 1; + + TransactionUtil.commit(); + + } catch (GenericEntityException e) { + // if there was an error, we'll just skip this product + TransactionUtil.rollback(); + Debug.logError(e, "Faild to import product["+product.get("productId")+"]. Error stack follows.", module); + } catch (Exception e) { + TransactionUtil.rollback(); + Debug.logError(e, "Faild to import product["+product.get("productId")+"]. Error stack follows.", module); + } + } + importProducts.close(); + + } catch (GenericEntityException e) { + String message = "Cannot import products: Unable to use delegator to retrieve data from the database. Error is: " + e.getMessage(); + Debug.logError(e, message, module); + return ServiceUtil.returnError(message); + } + + Map results = ServiceUtil.returnSuccess(); + results.put("productsImported", new Integer(imported)); + return results; + } + + /** + * Helper method to decode a DataImportProduct into a List of GenericValues modeling that product in the OFBiz schema. + * If for some reason obtaining data via the delegator fails, this service throws that exception. + * Note that everything is done with the delegator for maximum efficiency. + */ + private static List decodeProduct(GenericValue data, Timestamp now, String goodIdentificationTypeId1, String goodIdentificationTypeId2, GenericDelegator delegator) throws GenericEntityException, Exception { + Map input; + List toStore = FastList.newInstance(); + Debug.logInfo("Now processing data [" + data.get("productId") + "] description [" + data.get("description") + "]", module); + + // product + input = FastMap.newInstance(); + input.put("productId", data.get("productId")); + input.put("productTypeId", data.get("productTypeId")); + input.put("internalName", data.get("description")); + input.put("description", data.get("description")); + input.put("productName", data.get("description")); + input.put("productHeight", data.get("height")); + input.put("heightUomId", data.get("heightUomId")); + input.put("productDepth", data.get("productLength")); + input.put("depthUomId", data.get("productLengthUomId")); + input.put("productWidth", data.get("width")); + input.put("widthUomId", data.get("widthUomId")); + input.put("weight", data.get("weight")); + input.put("weightUomId", data.get("weightUomId")); + input.put("createdDate", now); + GenericValue product = delegator.makeValue("Product", input); + toStore.add(product); + + // product price + input = FastMap.newInstance(); + input.put("productId", product.get("productId")); + input.put("productPriceTypeId", "DEFAULT_PRICE"); + input.put("productPricePurposeId", "PURCHASE"); + input.put("productStoreGroupId", "_NA_"); + input.put("currencyUomId", data.get("priceCurrencyUomId")); + input.put("fromDate", now); + input.put("price", data.get("price")); + input.put("createdDate", now); + GenericValue productPrice = delegator.makeValue("ProductPrice", input); + toStore.add(productPrice); + + // good identification (this is per customIdN) + if (!UtilValidate.isEmpty(data.getString("customId1"))) { + input = FastMap.newInstance(); + input.put("goodIdentificationTypeId", goodIdentificationTypeId1); + input.put("productId", product.get("productId")); + input.put("idValue", data.get("customId1")); + GenericValue goodIdentification = delegator.makeValue("GoodIdentification", input); + toStore.add(goodIdentification); + } + if (!UtilValidate.isEmpty(data.getString("customId2"))) { + input = FastMap.newInstance(); + input.put("goodIdentificationTypeId", goodIdentificationTypeId2); + input.put("productId", product.get("productId")); + input.put("idValue", data.get("customId2")); + GenericValue goodIdentification = delegator.makeValue("GoodIdentification", input); + toStore.add(goodIdentification); + } + + // product features (this is per productFeatureN) + if (!UtilValidate.isEmpty(data.getString("productFeature1"))) { + String productFeatureId = data.getString("productFeature1"); + productFeatureId = productFeatureId.toUpperCase().replaceAll("\\s", "_"); + GenericValue productFeature = delegator.findByPrimaryKey("ProductFeature", UtilMisc.toMap("productFeatureId", productFeatureId)); + if (productFeature == null) { + input = FastMap.newInstance(); + input.put("productFeatureId", productFeatureId); + input.put("description", data.get("productFeature1")); + productFeature = delegator.makeValue("ProductFeature", input); + toStore.add(productFeature); + + input = FastMap.newInstance(); + input.put("productId", product.get("productId")); + input.put("productFeatureId", productFeatureId); + input.put("fromDate", now); + GenericValue productFeatureAppl = delegator.makeValue("ProductFeatureAppl", input); + toStore.add(productFeatureAppl); + } + } + + // update the original data record with a timestamp which also denotes that it has been processed (processedTimestamp = null was original search condition) + data.set("processedTimestamp", UtilDateTime.nowTimestamp()); + toStore.add(data); + + return toStore; + } +} |