You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ExcelAntWorkbookUtil.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.ss.excelant.util;
  16. import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
  17. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  18. import org.apache.poi.ss.formula.functions.FreeRefFunction;
  19. import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
  20. import org.apache.poi.ss.formula.udf.DefaultUDFFinder;
  21. import org.apache.poi.ss.formula.udf.UDFFinder;
  22. import org.apache.poi.ss.usermodel.*;
  23. import org.apache.poi.ss.util.CellReference;
  24. import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
  25. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  26. import org.apache.tools.ant.BuildException;
  27. import org.apache.tools.ant.Project;
  28. import org.apache.tools.ant.taskdefs.Typedef;
  29. import java.io.File;
  30. import java.io.FileInputStream;
  31. import java.util.ArrayList;
  32. import java.util.Date;
  33. import java.util.HashMap;
  34. import java.util.Iterator;
  35. /**
  36. * A general utility class that abstracts the POI details of loading the
  37. * workbook, accessing and updating cells.
  38. *
  39. * @author Jon Svede ( jon [at] loquatic [dot] com )
  40. * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
  41. *
  42. */
  43. public class ExcelAntWorkbookUtil extends Typedef {
  44. private String excelFileName;
  45. private Workbook workbook;
  46. private HashMap<String, FreeRefFunction> xlsMacroList;
  47. /**
  48. * Constructs an instance using a String that contains the fully qualified
  49. * path of the Excel file. This constructor initializes a Workbook instance
  50. * based on that file name.
  51. *
  52. * @param fName
  53. */
  54. protected ExcelAntWorkbookUtil(String fName) {
  55. excelFileName = fName;
  56. xlsMacroList = new HashMap<String, FreeRefFunction>() ;
  57. loadWorkbook();
  58. }
  59. /**
  60. * Constructs an instance based on a Workbook instance.
  61. *
  62. * @param wb
  63. */
  64. protected ExcelAntWorkbookUtil(Workbook wb) {
  65. workbook = wb;
  66. xlsMacroList = new HashMap<String, FreeRefFunction>() ;
  67. }
  68. /**
  69. * Loads the member variable workbook based on the fileName variable.
  70. * @return
  71. */
  72. private Workbook loadWorkbook() {
  73. File workbookFile = new File(excelFileName);
  74. try {
  75. FileInputStream fis = new FileInputStream(workbookFile);
  76. workbook = WorkbookFactory.create(fis);
  77. } catch(Exception e) {
  78. throw new BuildException("Cannot load file " + excelFileName
  79. + ". Make sure the path and file permissions are correct.", e);
  80. }
  81. return workbook ;
  82. }
  83. /**
  84. * Used to add a UDF to the evaluator.
  85. * @param name
  86. * @param clazzName
  87. * @throws ClassNotFoundException
  88. * @throws InstantiationException
  89. * @throws IllegalAccessException
  90. */
  91. public void addFunction( String name, String clazzName ) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
  92. Class clazzInst = Class.forName( clazzName ) ;
  93. Object newInst = clazzInst.newInstance() ;
  94. if( newInst instanceof FreeRefFunction ) {
  95. addFunction( name, (FreeRefFunction)newInst ) ;
  96. }
  97. }
  98. /**
  99. * Updates the internal HashMap of functions with instance and alias passed
  100. * in.
  101. *
  102. * @param name
  103. * @param func
  104. */
  105. protected void addFunction(String name, FreeRefFunction func) {
  106. xlsMacroList.put(name, func);
  107. }
  108. /**
  109. * returns a UDFFinder that contains all of the functions added.
  110. *
  111. * @return
  112. */
  113. protected UDFFinder getFunctions() {
  114. String[] names = new String[xlsMacroList.size()];
  115. FreeRefFunction[] functions = new FreeRefFunction[xlsMacroList.size()];
  116. Iterator<String> keysIt = xlsMacroList.keySet().iterator();
  117. int x = 0;
  118. while (keysIt.hasNext()) {
  119. String name = keysIt.next();
  120. FreeRefFunction function = xlsMacroList.get(name);
  121. names[x] = name;
  122. functions[x] = function;
  123. }
  124. UDFFinder udff1 = new DefaultUDFFinder(names, functions);
  125. UDFFinder udff = new AggregatingUDFFinder(udff1);
  126. return udff;
  127. }
  128. /**
  129. * Returns a formula evaluator that is loaded with the functions that
  130. * have been supplied.
  131. *
  132. * @param excelFileName
  133. * @return
  134. */
  135. protected FormulaEvaluator getEvaluator( String excelFileName ) {
  136. FormulaEvaluator evaluator ;
  137. if (excelFileName.endsWith(".xlsx")) {
  138. if( xlsMacroList != null && xlsMacroList.size() > 0 ) {
  139. evaluator = XSSFFormulaEvaluator.create( (XSSFWorkbook) workbook,
  140. null,
  141. getFunctions() ) ;
  142. }
  143. evaluator = new XSSFFormulaEvaluator((XSSFWorkbook) workbook);
  144. } else {
  145. if( xlsMacroList != null && xlsMacroList.size() > 0 ) {
  146. evaluator = HSSFFormulaEvaluator.create( (HSSFWorkbook)workbook,
  147. null,
  148. getFunctions() ) ;
  149. }
  150. evaluator = new HSSFFormulaEvaluator((HSSFWorkbook) workbook);
  151. }
  152. return evaluator ;
  153. }
  154. /**
  155. * Returns the Workbook instance associated with this WorkbookUtil.
  156. *
  157. * @return
  158. */
  159. public Workbook getWorkbook() {
  160. return workbook;
  161. }
  162. /**
  163. * Returns the fileName that was used to initialize this instance. May
  164. * return null if the instance was constructed from a Workbook object.
  165. *
  166. * @return
  167. */
  168. public String getFileName() {
  169. return excelFileName;
  170. }
  171. /**
  172. * Returns the list of sheet names.
  173. *
  174. * @return
  175. */
  176. public ArrayList<String> getSheets() {
  177. ArrayList<String> sheets = new ArrayList<String>() ;
  178. int sheetCount = workbook.getNumberOfSheets() ;
  179. for( int x=0; x<sheetCount; x++ ) {
  180. sheets.add( workbook.getSheetName( x ) ) ;
  181. }
  182. return sheets ;
  183. }
  184. /**
  185. * This method uses a String in standard Excel format (SheetName!CellId) to
  186. * locate the cell and set it to the value of the double in value.
  187. *
  188. * @param cellName
  189. * @param value
  190. */
  191. public void setDoubleValue(String cellName, double value) {
  192. log("starting setCellValue()", Project.MSG_DEBUG);
  193. Cell cell = getCell(cellName);
  194. log("working on cell: " + cell, Project.MSG_DEBUG);
  195. cell.setCellValue(value);
  196. log("after cell.setCellValue()", Project.MSG_DEBUG);
  197. log("set cell " + cellName + " to value " + value, Project.MSG_DEBUG);
  198. }
  199. /**
  200. * Utility method for setting the value of a Cell with a String.
  201. *
  202. * @param cellName
  203. * @param value
  204. */
  205. public void setStringValue( String cellName, String value ) {
  206. Cell cell = getCell(cellName);
  207. cell.setCellValue(value);
  208. }
  209. /**
  210. * Utility method for setting the value of a Cell with a Formula.
  211. *
  212. * @param cellName
  213. * @param formula
  214. */
  215. public void setFormulaValue( String cellName, String formula ) {
  216. Cell cell = getCell(cellName);
  217. cell.setCellFormula( formula );
  218. }
  219. /**
  220. * Utility method for setting the value of a Cell with a Date.
  221. * @param cellName
  222. * @param date
  223. */
  224. public void setDateValue( String cellName, Date date ) {
  225. Cell cell = getCell(cellName);
  226. cell.setCellValue( date ) ;
  227. }
  228. /**
  229. * Uses a String in standard Excel format (SheetName!CellId) to locate a
  230. * cell and evaluate it.
  231. *
  232. * @param cellName
  233. * @param expectedValue
  234. * @param precision
  235. */
  236. public ExcelAntEvaluationResult evaluateCell(String cellName, double expectedValue,
  237. double precision) {
  238. ExcelAntEvaluationResult evalResults = null;
  239. Cell cell = getCell(cellName);
  240. FormulaEvaluator evaluator = getEvaluator( excelFileName );
  241. CellValue resultOfEval = evaluator.evaluate(cell);
  242. if (resultOfEval.getErrorValue() == 0) {
  243. // the evaluation did not encounter errors
  244. double result = resultOfEval.getNumberValue();
  245. double delta = Math.abs(result - expectedValue);
  246. if (delta > precision) {
  247. evalResults = new ExcelAntEvaluationResult(false, false,
  248. resultOfEval.getNumberValue(),
  249. "Results was out of range based on precision " + " of "
  250. + precision + ". Delta was actually " + delta, delta, cellName );
  251. } else {
  252. evalResults = new ExcelAntEvaluationResult(false, true,
  253. resultOfEval.getNumberValue(),
  254. "Evaluation passed without error within in range.", delta, cellName );
  255. }
  256. } else {
  257. String errorMeaning = null ;
  258. try {
  259. errorMeaning = ErrorConstants.getText( resultOfEval
  260. .getErrorValue() ) ;
  261. } catch( IllegalArgumentException iae ) {
  262. errorMeaning = "unknown error code: " +
  263. Byte.toString( resultOfEval.getErrorValue() ) ;
  264. }
  265. evalResults = new ExcelAntEvaluationResult(false, false,
  266. resultOfEval.getNumberValue(),
  267. "Evaluation failed due to an evaluation error of "
  268. + resultOfEval.getErrorValue()
  269. + " which is "
  270. + errorMeaning, 0, cellName );
  271. }
  272. return evalResults;
  273. }
  274. /**
  275. * Returns a Cell as a String value.
  276. *
  277. * @param cellName
  278. * @return
  279. */
  280. public String getCellAsString( String cellName ) {
  281. Cell cell = getCell( cellName ) ;
  282. if( cell != null ) {
  283. return cell.getStringCellValue() ;
  284. }
  285. return "" ;
  286. }
  287. /**
  288. * Returns the value of the Cell as a double.
  289. *
  290. * @param cellName
  291. * @return
  292. */
  293. public double getCellAsDouble( String cellName ) {
  294. Cell cell = getCell( cellName ) ;
  295. if( cell != null ) {
  296. return cell.getNumericCellValue() ;
  297. }
  298. return 0.0 ;
  299. }
  300. /**
  301. * Returns a cell reference based on a String in standard Excel format
  302. * (SheetName!CellId). This method will create a new cell if the
  303. * requested cell isn't initialized yet.
  304. *
  305. * @param cellName
  306. * @return
  307. */
  308. private Cell getCell(String cellName) {
  309. CellReference cellRef = new CellReference(cellName);
  310. String sheetName = cellRef.getSheetName();
  311. Sheet sheet = workbook.getSheet(sheetName);
  312. if(sheet == null) {
  313. throw new BuildException("Sheet not found: " + sheetName);
  314. }
  315. int rowIdx = cellRef.getRow();
  316. int colIdx = cellRef.getCol();
  317. Row row = sheet.getRow(rowIdx);
  318. if( row == null ) {
  319. row = sheet.createRow( rowIdx ) ;
  320. }
  321. Cell cell = row.getCell(colIdx);
  322. if( cell == null ) {
  323. cell = row.createCell( colIdx ) ;
  324. }
  325. return cell;
  326. }
  327. }