X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=server%2Fruntime%2Forg.argeo.server.jxl%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fserver%2Fjxl%2Fdao%2FJxlDaoSupport.java;h=7b4110d8e487e31428398d37ccc7791f4dca5092;hb=c5bb48d71ad5d71e389137e5fb95f96d9005a942;hp=390fae72be070277692ad22dd19e06cc89476aaa;hpb=db84ccc332884c4b89b755923538cecf2f00df68;p=lgpl%2Fargeo-commons.git diff --git a/server/runtime/org.argeo.server.jxl/src/main/java/org/argeo/server/jxl/dao/JxlDaoSupport.java b/server/runtime/org.argeo.server.jxl/src/main/java/org/argeo/server/jxl/dao/JxlDaoSupport.java index 390fae72b..7b4110d8e 100644 --- a/server/runtime/org.argeo.server.jxl/src/main/java/org/argeo/server/jxl/dao/JxlDaoSupport.java +++ b/server/runtime/org.argeo.server.jxl/src/main/java/org/argeo/server/jxl/dao/JxlDaoSupport.java @@ -2,131 +2,338 @@ package org.argeo.server.jxl.dao; import java.io.InputStream; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.TreeMap; import jxl.Cell; import jxl.FormulaCell; +import jxl.JXLException; import jxl.Sheet; import jxl.Workbook; +import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.server.ArgeoServerException; +import org.argeo.server.dao.LightDaoSupport; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeanWrapperImpl; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.generic.GenericBeanFactoryAccessor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.io.Resource; +import org.springframework.util.StringUtils; -public class JxlDaoSupport { +public class JxlDaoSupport implements LightDaoSupport, ApplicationContextAware, + InitializingBean { private final static Log log = LogFactory.getLog(JxlDaoSupport.class); private ClassLoader classLoader = getClass().getClassLoader(); + private ApplicationContext applicationContext; - private Map> model = new HashMap>(); + private Map, Map> model = new HashMap, Map>(); - public void load(InputStream in) { + private Map externalRefs = new HashMap(); - try { - // used to resolve inner references - Map> tempRefs = new HashMap>(); - List links = new ArrayList(); + private List scannedPackages = new ArrayList(); - Workbook workbook = Workbook.getWorkbook(in); + private List workbooks = new ArrayList(); + + public void afterPropertiesSet() throws Exception { + init(); + } + + public void init() { + // used to resolve inner references + Map> tempRefs = new HashMap>(); + + List references = new ArrayList(); + + for (Resource res : workbooks) { + InputStream in = null; + try { + in = res.getInputStream(); + load(in, references, tempRefs); + } catch (Exception e) { + throw new ArgeoServerException("Cannot load stream", e); + } finally { + IOUtils.closeQuietly(in); + } + } + + // Inject references + for (Reference ref : references) { + injectReference(ref, tempRefs); + } + if (log.isDebugEnabled()) + log.debug(references.size() + " references linked"); + } + public void load(InputStream in, List references, + Map> tempRefs) { + try { + Workbook workbook = Workbook.getWorkbook(in); for (Sheet sheet : workbook.getSheets()) { - if (log.isDebugEnabled()) - log - .debug("Instantiate objects of sheet " - + sheet.getName()); - - Cell[] firstRow = sheet.getRow(0); - - // TODO: ability to map sheet names and class names - String className = sheet.getName(); - Class clss = classLoader.loadClass(className); - model.put(clss, new HashMap()); - - tempRefs.put(sheet.getName(), new ArrayList()); - - String keyProperty = firstRow[0].getContents(); - for (int i = 1; i < sheet.getRows(); i++) { - if (log.isTraceEnabled()) - log.trace(" row " + i); - - Cell[] currentRow = sheet.getRow(i); - BeanWrapper bw = new BeanWrapperImpl(clss); - for (int j = 0; j < firstRow.length; j++) { - String pName = firstRow[j].getContents(); - - Cell cell = currentRow[j]; - if (cell instanceof FormulaCell) { - String formula = ((FormulaCell) cell).getFormula(); - int index = formula.indexOf('!'); - String targetSheet = formula.substring(0, index); - // assume no double letters - Integer targetRow = Integer.parseInt(formula - .substring(index + 2)); - links.add(new Link(bw.getWrappedInstance(), pName, - targetSheet, targetRow)); - - if (log.isTraceEnabled()) - log.debug(" formula: " + formula - + " | content: " + cell.getContents() - + " | targetSheet=" + targetSheet - + ", targetRow=" + targetRow); - } else { - bw.setPropertyValue(pName, cell.getContents()); - - if (log.isTraceEnabled()) - log.debug(" " + pName + "=" - + cell.getContents()); - } - }// properties set - - model.get(clss).put(bw.getPropertyValue(keyProperty), - bw.getWrappedInstance()); - tempRefs.get(sheet.getName()).add(bw.getWrappedInstance()); + loadSheet(sheet, references, tempRefs); + } + } catch (Exception e) { + throw new ArgeoServerException("Cannot load workbook", e); + } + } + + protected void loadSheet(Sheet sheet, List references, + Map> tempRefs) throws JXLException { + if (log.isTraceEnabled()) + log.debug("Instantiate sheet " + sheet.getName()); + + Cell[] firstRow = sheet.getRow(0); + + Class clss = findClassToInstantiate(sheet); + model.put(clss, new TreeMap()); + + tempRefs.put(sheet.getName(), new ArrayList()); + + String keyProperty = firstRow[0].getContents(); + for (int row = 1; row < sheet.getRows(); row++) { + if (log.isTraceEnabled()) + log.trace(" row " + row); + + Cell[] currentRow = sheet.getRow(row); + BeanWrapper bw = new BeanWrapperImpl(clss); + cells: for (int col = 0; col < firstRow.length; col++) { + String pName = firstRow[col].getContents(); + + if (col < currentRow.length) { + Cell cell = currentRow[col]; + if (overrideCell(cell, bw, pName, keyProperty, row, + references, tempRefs)) + continue cells; + loadCell(cell, bw, pName, keyProperty, row, references); } + }// cells + + model.get(clss).put(bw.getPropertyValue(keyProperty), + bw.getWrappedInstance()); + tempRefs.get(sheet.getName()).add(bw.getWrappedInstance()); + } + + if (log.isDebugEnabled()) + log.debug(model.get(clss).size() + " objects of type " + clss + + " instantiated"); - if (log.isDebugEnabled()) - log.debug(model.get(clss).size() + " objects of type " - + clss); + } + + protected void loadCell(Cell cell, BeanWrapper bw, String propertyName, + String keyProperty, Integer row, List references) + throws JXLException { + + if (cell instanceof FormulaCell) { + String formula = ((FormulaCell) cell).getFormula(); + int index = formula.indexOf('!'); + if (index < 0) + throw new ArgeoServerException("Cannot interpret formula " + + formula); + ; + String targetSheet = formula.substring(0, index); + // assume no double letters!! + String targetRowStr = formula.substring(index + 2); + if (targetRowStr.charAt(0) == '$') + targetRowStr = targetRowStr.substring(1); + Integer targetRow = Integer.parseInt(targetRowStr); + references.add(new Reference(bw.getWrappedInstance(), propertyName, + targetSheet, targetRow)); + + if (log.isTraceEnabled()) + log.debug(" formula: " + formula + " | content: " + + cell.getContents() + " | targetSheet=" + targetSheet + + ", targetRow=" + targetRow); + } else { + String contents = cell.getContents(); + if (propertyName.equals(keyProperty) + && !StringUtils.hasText(contents)) { + // auto allocate key column if empty + contents = Integer.toString(row); } - if (log.isDebugEnabled()) - log.debug("Link " + links.size() + " references"); - for (Link link : links) { - BeanWrapper bw = new BeanWrapperImpl(link.object); - Object targetObject = tempRefs.get(link.getTargetSheet()).get( - link.targetRow - 2); - bw.setPropertyValue(link.property, targetObject); + if (propertyName.charAt(0) == '#') {// externalRef + references.add(new Reference(bw.getWrappedInstance(), + propertyName.substring(1), contents)); + } else { + bw.setPropertyValue(propertyName, contents); } - } catch (Exception e) { - throw new ArgeoServerException("Cannot load workbook", e); + if (log.isTraceEnabled()) + log.debug(" " + propertyName + "=" + contents); } + + } + + /** Returns true if property was set (thus bypassing standard process). */ + protected Boolean overrideCell(Cell cell, BeanWrapper bw, + String propertyName, String keyProperty, Integer row, + List references, Map> tempRefs) { + return false; + } + + protected void injectReference(Reference reference, + Map> tempRefs) { + BeanWrapper bw = new BeanWrapperImpl(reference.object); + Object targetObject; + if (reference.getExternalRef() != null) { + String ref = reference.getExternalRef(); + if (externalRefs.containsKey(ref)) + targetObject = externalRefs.get(ref); + else if (applicationContext != null) + targetObject = applicationContext.getBean(ref); + else { + targetObject = null; + log.warn("Ref " + ref + " not found"); + } + } else { + targetObject = tempRefs.get(reference.getTargetSheet()).get( + reference.targetRow - 2); + } + bw.setPropertyValue(reference.property, targetObject); + + } + + protected Class findClassToInstantiate(Sheet sheet) { + // TODO: ability to map sheet names and class names + String className = sheet.getName(); + Class clss = null; + try { + clss = classLoader.loadClass(className); + return clss; + } catch (ClassNotFoundException e) { + // silent + } + + scannedPkgs: for (String pkg : scannedPackages) { + try { + clss = classLoader.loadClass(pkg.trim() + "." + className); + break scannedPkgs; + } catch (ClassNotFoundException e) { + // silent + if (log.isTraceEnabled()) + log.trace(e.getMessage()); + } + } + + if (clss == null) + throw new ArgeoServerException("Cannot find a class for sheet " + + sheet.getName()); + + return clss; } @SuppressWarnings("unchecked") public T getByKey(Class clss, Object key) { - return (T) model.get(clss).get(key); + return (T) model.get(findClass(clss)).get(key); + } + + /** + * Slow. + * + * @return the first found + */ + public T getByField(Class clss, String field, Object value) { + List all = list(clss, null); + T res = null; + for (T obj : all) { + if (new BeanWrapperImpl(obj).getPropertyValue(field).equals(value)) { + res = obj; + break; + } + } + return res; + } + + @SuppressWarnings("unchecked") + public List list(Class clss, Object filter) { + List res = new ArrayList(); + + Class classToUse = findClass(clss); + if (classToUse != null) + res.addAll((Collection) model.get(classToUse).values()); + + if (applicationContext != null) + res.addAll(new GenericBeanFactoryAccessor(applicationContext) + .getBeansOfType(clss).values()); + + return res; + } + + @SuppressWarnings("unchecked") + protected Class findClass(Class parent) { + if (model.containsKey(parent)) + return parent; + + for (Class clss : model.keySet()) { + if (parent.isAssignableFrom(clss)) + return clss;// return the first found + } + return null; } - public static class Link { + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } + + public void setExternalRefs(Map externalRefs) { + this.externalRefs = externalRefs; + } + + public Map getExternalRefs() { + return externalRefs; + } + + public void setScannedPackages(List scannedPackages) { + this.scannedPackages = scannedPackages; + } + + public List getScannedPackages() { + return scannedPackages; + } + + public void setWorkbooks(List workbooks) { + this.workbooks = workbooks; + } + + public List getWorkbooks() { + return workbooks; + } + + public void setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public static class Reference { private Object object; private String property; private String targetSheet; private Integer targetRow; + private String externalRef; - public Link(Object object, String property, String targetSheet, + public Reference(Object object, String property, String targetSheet, Integer targetRow) { - super(); this.object = object; this.property = property; this.targetSheet = targetSheet; this.targetRow = targetRow; } + public Reference(Object object, String property, String externalRef) { + this.object = object; + this.property = property; + this.externalRef = externalRef; + } + public Object getObject() { return object; } @@ -143,5 +350,9 @@ public class JxlDaoSupport { return targetRow; } + public String getExternalRef() { + return externalRef; + } + } }