2 * Copyright (C) 2007-2012 Argeo GmbH
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.argeo
.server
.jxl
.dao
;
18 import java
.io
.InputStream
;
19 import java
.util
.ArrayList
;
20 import java
.util
.HashMap
;
21 import java
.util
.List
;
22 import java
.util
.Locale
;
24 import java
.util
.StringTokenizer
;
28 import jxl
.FormulaCell
;
29 import jxl
.JXLException
;
31 import jxl
.NumberCell
;
34 import jxl
.WorkbookSettings
;
36 import org
.apache
.commons
.logging
.Log
;
37 import org
.apache
.commons
.logging
.LogFactory
;
38 import org
.argeo
.ArgeoException
;
39 import org
.argeo
.server
.dao
.AbstractTabularDaoSupport
;
40 import org
.argeo
.server
.dao
.LightDaoSupport
;
41 import org
.springframework
.beans
.BeanWrapper
;
42 import org
.springframework
.beans
.factory
.InitializingBean
;
43 import org
.springframework
.context
.ApplicationContextAware
;
44 import org
.springframework
.util
.StringUtils
;
46 public class JxlDaoSupport
extends AbstractTabularDaoSupport
implements
47 LightDaoSupport
, ApplicationContextAware
, InitializingBean
{
48 private final static Log log
= LogFactory
.getLog(JxlDaoSupport
.class);
50 private String encoding
= "cp1252";
51 private Locale locale
= null;
53 protected void load(InputStream in
, List
<Reference
> references
) {
55 WorkbookSettings workbookSettings
= new WorkbookSettings();
56 workbookSettings
.setEncoding(encoding
);
58 workbookSettings
.setLocale(locale
);
59 Workbook workbook
= Workbook
.getWorkbook(in
, workbookSettings
);
60 for (Sheet sheet
: workbook
.getSheets()) {
61 loadSheet(sheet
, references
);
63 } catch (Exception e
) {
64 throw new ArgeoException("Cannot load workbook", e
);
68 protected void loadSheet(Sheet sheet
, List
<Reference
> references
)
70 String sheetName
= sheet
.getName();
71 if (log
.isTraceEnabled())
72 log
.debug("Instantiate sheet " + sheetName
);
75 int hashIndex
= sheetName
.lastIndexOf('#');
77 tableName
= sheetName
.substring(0, hashIndex
);
79 tableName
= sheetName
;
82 Class
<?
> clss
= findClassToInstantiate(tableName
);
86 // http://stackoverflow.com/questions/451452/valid-characters-for-excel-sheet-names
87 BeanWrapper bw
= newBeanWrapper(clss
);
88 StringTokenizer espSt
= new StringTokenizer(sheetName
89 .substring(hashIndex
+ 1), "&=");
90 String keyProperty
= null;
91 while (espSt
.hasMoreTokens()) {
92 String fieldName
= espSt
.nextToken();
93 if (keyProperty
== null)
94 keyProperty
= fieldName
;
95 if (!espSt
.hasMoreTokens())
96 throw new ArgeoException("Badly formatted sheetname "
98 String fieldValue
= espSt
.nextToken();
99 bw
.setPropertyValue(fieldName
, fieldValue
);
100 loadAsObject(bw
, sheet
, references
);
101 saveOrUpdate(bw
.getPropertyValue(keyProperty
), bw
102 .getWrappedInstance(), clss
);
107 Cell
[] firstRow
= sheet
.getRow(0);
108 String keyProperty
= firstRow
[0].getContents();
110 if (keyProperty
.charAt(keyProperty
.length() - 1) == '>') {
111 loadAsColumns(clss
, keyProperty
.substring(0, keyProperty
112 .length() - 1), sheet
, firstRow
, references
);
114 loadAsRows(clss
, keyProperty
, sheet
, firstRow
, references
);
119 protected void loadAsRows(Class
<?
> clss
, String keyProperty
, Sheet sheet
,
120 Cell
[] firstRow
, List
<Reference
> references
) throws JXLException
{
121 for (int row
= 1; row
< sheet
.getRows(); row
++) {
122 if (log
.isTraceEnabled())
123 log
.trace(" row " + row
);
125 Cell
[] currentRow
= sheet
.getRow(row
);
126 BeanWrapper bw
= newBeanWrapper(clss
);
127 cells
: for (int col
= 0; col
< firstRow
.length
; col
++) {
128 String pName
= firstRow
[col
].getContents();
130 if (col
< currentRow
.length
) {
131 Cell cell
= currentRow
[col
];
132 if (overrideCell(cell
, bw
, pName
, keyProperty
, row
,
135 loadCell(cell
, bw
, pName
, keyProperty
, row
, references
);
139 saveOrUpdate(bw
.getPropertyValue(keyProperty
), bw
140 .getWrappedInstance(), clss
);
141 // tempRefs.get(sheet.getName()).add(bw.getWrappedInstance());
142 registerInTabularView(sheet
.getName(), bw
.getWrappedInstance());
146 protected void loadAsColumns(Class
<?
> clss
, String keyProperty
,
147 Sheet sheet
, Cell
[] firstRow
, List
<Reference
> references
)
148 throws JXLException
{
149 Cell
[] firstColumn
= sheet
.getColumn(0);
151 for (int col
= 1; col
< firstRow
.length
; col
++) {
152 if (log
.isTraceEnabled())
153 log
.trace(" column " + col
);
154 BeanWrapper bw
= newBeanWrapper(clss
);
155 Cell
[] column
= sheet
.getColumn(col
);
156 for (int row
= 0; row
< column
.length
; row
++) {
157 Cell cell
= column
[row
];
161 propertyName
= keyProperty
;
163 propertyName
= firstColumn
[row
].getContents();
165 Class
<?
> rowType
= bw
.getPropertyType(propertyName
);
166 if (log
.isTraceEnabled())
167 log
.trace(" " + propertyName
+ " rowType="
168 + rowType
.getName());
169 if (Map
.class.isAssignableFrom(rowType
)) {
170 if (log
.isTraceEnabled())
171 log
.trace(" start building map " + propertyName
);
173 Map
<Object
, Object
> map
= new HashMap
<Object
, Object
>();
174 String firstColContents
= firstColumn
[row
].getContents();
175 mapRows
: for (; row
< column
.length
; row
++) {
177 Object key
= firstColContents
;
178 if (log
.isTraceEnabled())
179 log
.trace(" row=" + row
+ ", firstColContents="
180 + firstColContents
+ ", key=" + key
181 + ", type=" + cell
.getType());
182 Object cellValue
= getCellValue(cell
);
183 map
.put(key
, cellValue
);
185 // check next row too see if one should break
186 if (row
< firstColumn
.length
- 1)
187 firstColContents
= firstColumn
[row
+ 1]
189 if (bw
.isWritableProperty(firstColContents
)
190 || firstColContents
.trim().equals("")
191 || row
== firstColumn
.length
- 1) {
192 bw
.setPropertyValue(propertyName
, map
);
193 if (log
.isTraceEnabled())
194 log
.trace(" set map " + propertyName
195 + " of size " + map
.size());
196 break mapRows
;// map is over
200 loadCell(cell
, bw
, propertyName
, keyProperty
, row
,
205 saveOrUpdate(bw
.getPropertyValue(keyProperty
), bw
206 .getWrappedInstance(), clss
);
207 // tempRefs.get(sheet.getName()).add(bw.getWrappedInstance());
208 registerInTabularView(sheet
.getName(), bw
.getWrappedInstance());
212 protected void loadAsObject(BeanWrapper bw
, Sheet sheet
,
213 List
<Reference
> references
) {
214 Cell
[] firstColumn
= sheet
.getColumn(0);
215 for (int row
= 0; row
< firstColumn
.length
; row
++) {
216 if (log
.isTraceEnabled())
217 log
.trace(" row " + row
);
218 Cell
[] currentRow
= sheet
.getRow(row
);
219 String propertyName
= firstColumn
[row
].getContents();
220 Class
<?
> rowType
= bw
.getPropertyType(propertyName
);
221 if (Map
.class.isAssignableFrom(rowType
)) {
222 Map
<Object
, Object
> map
= new HashMap
<Object
, Object
>();
223 if (currentRow
.length
== 1
224 || currentRow
[1].getContents().trim().equals("")) {
228 List
<Object
> subKeys
= new ArrayList
<Object
>();
229 for (int col
= 1; col
< currentRow
.length
; col
++) {
230 subKeys
.add(getCellValue(currentRow
[col
]));
232 if (log
.isTraceEnabled())
233 log
.trace(" subKeys=" + subKeys
);
235 String firstColContents
= firstColumn
[row
].getContents();
236 mapRows
: for (; row
< firstColumn
.length
; row
++) {
237 currentRow
= sheet
.getRow(row
);
239 Object key
= firstColContents
;
240 Map
<Object
, Object
> subMap
= new HashMap
<Object
, Object
>();
242 for (int col
= 1; col
< currentRow
.length
243 && col
< subKeys
.size() + 1; col
++) {
244 Object subKey
= subKeys
.get(col
- 1);
245 Cell cell
= currentRow
[col
];
246 if (log
.isTraceEnabled())
247 log
.trace(" row=" + row
248 + ", firstColContents="
249 + firstColContents
+ ", subKey="
250 + subKey
+ ", type=" + cell
.getType());
251 Object cellValue
= getCellValue(cell
);
252 subMap
.put(subKey
, cellValue
);
254 map
.put(key
, subMap
);
256 // check next row too see if one should break
257 if (row
< firstColumn
.length
- 1)
258 firstColContents
= firstColumn
[row
+ 1]
260 if (bw
.isWritableProperty(firstColContents
)
261 || firstColContents
.trim().equals("")
262 || row
== firstColumn
.length
- 1) {
264 bw
.setPropertyValue(propertyName
, map
);
265 if (log
.isTraceEnabled())
266 log
.trace(" set map " + propertyName
267 + " of size " + map
.size());
268 break mapRows
;// map is over
273 } else if (List
.class.isAssignableFrom(rowType
)) {
274 throw new UnsupportedOperationException();
276 bw
.setPropertyValue(propertyName
, getCellValue(currentRow
[1]));
281 protected void loadCell(Cell cell
, BeanWrapper bw
, String propertyName
,
282 String keyProperty
, Integer row
, List
<Reference
> references
)
283 throws JXLException
{
285 if (cell
instanceof FormulaCell
) {
286 String formula
= ((FormulaCell
) cell
).getFormula();
287 int index
= formula
.indexOf('!');
289 throw new ArgeoException("Cannot interpret formula "
292 String targetSheet
= formula
.substring(0, index
);
293 // assume no double letters!!
294 String targetRowStr
= formula
.substring(index
+ 2);
295 if (targetRowStr
.charAt(0) == '$')
296 targetRowStr
= targetRowStr
.substring(1);
297 Integer targetRow
= Integer
.parseInt(targetRowStr
);
298 references
.add(new TabularInternalReference(
299 bw
.getWrappedInstance(), propertyName
, targetSheet
,
302 if (log
.isTraceEnabled())
303 log
.debug(" formula: " + formula
+ " | content: "
304 + cell
.getContents() + " | targetSheet=" + targetSheet
305 + ", targetRow=" + targetRow
);
307 Object cellValue
= getCellValue(cell
);
309 if (propertyName
.equals(keyProperty
)
310 && !StringUtils
.hasText(cellValue
.toString())) {
311 // auto allocate key column if empty
312 cellValue
= Integer
.toString(row
);
315 if (propertyName
.charAt(0) == '#') {// externalRef
316 references
.add(new Reference(bw
.getWrappedInstance(),
317 propertyName
.substring(1), cellValue
.toString()));
319 bw
.setPropertyValue(propertyName
, cellValue
);
322 if (log
.isTraceEnabled())
323 log
.debug(" " + propertyName
+ "=" + cellValue
);
328 protected Object
getCellValue(Cell cell
) {
330 if (cell
.getType() == CellType
.LABEL
) {
331 LabelCell lc
= (LabelCell
) cell
;
332 contents
= lc
.getString();
333 } else if (cell
.getType() == CellType
.NUMBER
) {
334 NumberCell nc
= (NumberCell
) cell
;
335 contents
= nc
.getValue();
337 contents
= cell
.getContents();
342 /** Returns true if property was set (thus bypassing standard process). */
343 protected Boolean
overrideCell(Cell cell
, BeanWrapper bw
,
344 String propertyName
, String keyProperty
, Integer row
,
345 List
<Reference
> references
) {
349 public void setEncoding(String encoding
) {
350 this.encoding
= encoding
;
353 public void setLocale(Locale locale
) {
354 this.locale
= locale
;