]> source.dussan.org Git - poi.git/commitdiff
Initial add of ForkedEvaluator functionality
authorJosh Micich <josh@apache.org>
Thu, 4 Dec 2008 02:48:24 +0000 (02:48 +0000)
committerJosh Micich <josh@apache.org>
Thu, 4 Dec 2008 02:48:24 +0000 (02:48 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@723194 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationCell.java [new file with mode: 0644]
src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationSheet.java [new file with mode: 0644]
src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java [new file with mode: 0644]
src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluator.java [new file with mode: 0644]

diff --git a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationCell.java b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationCell.java
new file mode 100644 (file)
index 0000000..3563904
--- /dev/null
@@ -0,0 +1,132 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.ss.formula.eval.forked;\r
+\r
+import org.apache.poi.hssf.record.formula.eval.BlankEval;\r
+import org.apache.poi.hssf.record.formula.eval.BoolEval;\r
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;\r
+import org.apache.poi.hssf.record.formula.eval.NumberEval;\r
+import org.apache.poi.hssf.record.formula.eval.StringEval;\r
+import org.apache.poi.hssf.record.formula.eval.ValueEval;\r
+import org.apache.poi.hssf.usermodel.HSSFCell;\r
+import org.apache.poi.ss.formula.EvaluationCell;\r
+import org.apache.poi.ss.formula.EvaluationSheet;\r
+import org.apache.poi.ss.usermodel.Cell;\r
+\r
+/**\r
+ * Represents a cell being used for forked evaluation that has had a value set different from the\r
+ * corresponding cell in the shared master workbook.\r
+ *\r
+ * @author Josh Micich\r
+ */\r
+final class ForkedEvaluationCell implements EvaluationCell {\r
+\r
+       private final EvaluationSheet _sheet;\r
+       /** corresponding cell from master workbook */\r
+       private final EvaluationCell _masterCell;\r
+       private boolean _booleanValue;\r
+       private int _cellType;\r
+       private int _errorValue;\r
+       private double _numberValue;\r
+       private String _stringValue;\r
+\r
+       public ForkedEvaluationCell(ForkedEvaluationSheet sheet, EvaluationCell masterCell) {\r
+               _sheet = sheet;\r
+               _masterCell = masterCell;\r
+               // start with value blank, but expect construction to be immediately\r
+               setValue(BlankEval.INSTANCE); // followed by a proper call to setValue()\r
+       }\r
+\r
+       public Object getIdentityKey() {\r
+               return _masterCell.getIdentityKey();\r
+       }\r
+\r
+       public void setValue(ValueEval value) {\r
+               Class<? extends ValueEval> cls = value.getClass();\r
+\r
+               if (cls == NumberEval.class) {\r
+                       _cellType = HSSFCell.CELL_TYPE_NUMERIC;\r
+                       _numberValue = ((NumberEval)value).getNumberValue();\r
+                       return;\r
+               }\r
+               if (cls == StringEval.class) {\r
+                       _cellType = HSSFCell.CELL_TYPE_STRING;\r
+                       _stringValue = ((StringEval)value).getStringValue();\r
+                       return;\r
+               }\r
+               if (cls == BoolEval.class) {\r
+                       _cellType = HSSFCell.CELL_TYPE_BOOLEAN;\r
+                       _booleanValue = ((BoolEval)value).getBooleanValue();\r
+                       return;\r
+               }\r
+               if (cls == ErrorEval.class) {\r
+                       _cellType = HSSFCell.CELL_TYPE_ERROR;\r
+                       _errorValue = ((ErrorEval)value).getErrorCode();\r
+                       return;\r
+               }\r
+               if (cls == BlankEval.class) {\r
+                       _cellType = HSSFCell.CELL_TYPE_BLANK;\r
+                       return;\r
+               }\r
+               throw new IllegalArgumentException("Unexpected value class (" + cls.getName() + ")");\r
+       }\r
+       public void copyValue(Cell destCell) {\r
+               switch (_cellType) {\r
+                       case Cell.CELL_TYPE_BLANK:   destCell.setCellType(Cell.CELL_TYPE_BLANK);    return;\r
+                       case Cell.CELL_TYPE_NUMERIC: destCell.setCellValue(_numberValue);           return;\r
+                       case Cell.CELL_TYPE_BOOLEAN: destCell.setCellValue(_booleanValue);          return;\r
+                       case Cell.CELL_TYPE_STRING:  destCell.setCellValue(_stringValue);           return;\r
+                       case Cell.CELL_TYPE_ERROR:   destCell.setCellErrorValue((byte)_errorValue); return;\r
+               }\r
+               throw new IllegalStateException("Unexpected data type (" + _cellType + ")");\r
+       }\r
+\r
+       private void checkCellType(int expectedCellType) {\r
+               if (_cellType != expectedCellType) {\r
+                       throw new RuntimeException("Wrong data type (" + _cellType + ")");\r
+               }\r
+       }\r
+       public int getCellType() {\r
+               return _cellType;\r
+       }\r
+       public boolean getBooleanCellValue() {\r
+               checkCellType(HSSFCell.CELL_TYPE_BOOLEAN);\r
+               return _booleanValue;\r
+       }\r
+       public int getErrorCellValue() {\r
+               checkCellType(HSSFCell.CELL_TYPE_ERROR);\r
+               return _errorValue;\r
+       }\r
+       public double getNumericCellValue() {\r
+               checkCellType(HSSFCell.CELL_TYPE_NUMERIC);\r
+               return _numberValue;\r
+       }\r
+       public String getStringCellValue() {\r
+               checkCellType(HSSFCell.CELL_TYPE_STRING);\r
+               return _stringValue;\r
+       }\r
+       public EvaluationSheet getSheet() {\r
+               return _sheet;\r
+       }\r
+       public int getRowIndex() {\r
+               return _masterCell.getRowIndex();\r
+       }\r
+       public int getColumnIndex() {\r
+               return _masterCell.getColumnIndex();\r
+       }\r
+}\r
diff --git a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationSheet.java b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationSheet.java
new file mode 100644 (file)
index 0000000..837ba93
--- /dev/null
@@ -0,0 +1,129 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.ss.formula.eval.forked;\r
+\r
+import java.util.Arrays;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import org.apache.poi.ss.formula.EvaluationCell;\r
+import org.apache.poi.ss.formula.EvaluationSheet;\r
+import org.apache.poi.ss.formula.EvaluationWorkbook;\r
+import org.apache.poi.ss.usermodel.Cell;\r
+import org.apache.poi.ss.usermodel.Row;\r
+import org.apache.poi.ss.usermodel.Sheet;\r
+\r
+/**\r
+ * Represents a sheet being used for forked evaluation.  Initially, objects of this class contain\r
+ * only the cells from the master workbook. By calling {@link #getOrCreateUpdatableCell(int, int)},\r
+ * the master cell object is logically replaced with a {@link ForkedEvaluationCell} instance, which\r
+ * will be used in all subsequent evaluations.\r
+ *\r
+ * @author Josh Micich\r
+ */\r
+final class ForkedEvaluationSheet implements EvaluationSheet {\r
+\r
+       private final EvaluationSheet _masterSheet;\r
+       /**\r
+        * Only cells which have been split are put in this map.  (This has been done to conserve memory).\r
+        */\r
+       private final Map<RowColKey, ForkedEvaluationCell> _sharedCellsByRowCol;\r
+\r
+       public ForkedEvaluationSheet(EvaluationSheet masterSheet) {\r
+               _masterSheet = masterSheet;\r
+               _sharedCellsByRowCol = new HashMap<RowColKey, ForkedEvaluationCell>();\r
+       }\r
+\r
+       public EvaluationCell getCell(int rowIndex, int columnIndex) {\r
+               RowColKey key = new RowColKey(rowIndex, columnIndex);\r
+\r
+               ForkedEvaluationCell result = _sharedCellsByRowCol.get(key);\r
+               if (result == null) {\r
+                       return _masterSheet.getCell(rowIndex, columnIndex);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       public ForkedEvaluationCell getOrCreateUpdatableCell(int rowIndex, int columnIndex) {\r
+               RowColKey key = new RowColKey(rowIndex, columnIndex);\r
+\r
+               ForkedEvaluationCell result = _sharedCellsByRowCol.get(key);\r
+               if (result == null) {\r
+                       EvaluationCell mcell = _masterSheet.getCell(rowIndex, columnIndex);\r
+                       result = new ForkedEvaluationCell(this, mcell);\r
+                       _sharedCellsByRowCol.put(key, result);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       public void copyUpdatedCells(Sheet sheet) {\r
+               RowColKey[] keys = new RowColKey[_sharedCellsByRowCol.size()];\r
+               _sharedCellsByRowCol.keySet().toArray(keys);\r
+               Arrays.sort(keys);\r
+               for (int i = 0; i < keys.length; i++) {\r
+                       RowColKey key = keys[i];\r
+                       Row row = sheet.getRow(key.getRowIndex());\r
+                       if (row == null) {\r
+                               row = sheet.createRow(key.getRowIndex());\r
+                       }\r
+                       Cell destCell = row.getCell(key.getColumnIndex());\r
+                       if (destCell == null) {\r
+                               destCell = row.createCell(key.getColumnIndex());\r
+                       }\r
+\r
+                       ForkedEvaluationCell srcCell = _sharedCellsByRowCol.get(key);\r
+                       srcCell.copyValue(destCell);\r
+               }\r
+       }\r
+\r
+       public int getSheetIndex(EvaluationWorkbook mewb) {\r
+               return mewb.getSheetIndex(_masterSheet);\r
+       }\r
+\r
+       private static final class RowColKey implements Comparable<RowColKey>{\r
+               private final int _rowIndex;\r
+               private final int _columnIndex;\r
+\r
+               public RowColKey(int rowIndex, int columnIndex) {\r
+                       _rowIndex = rowIndex;\r
+                       _columnIndex = columnIndex;\r
+               }\r
+               @Override\r
+               public boolean equals(Object obj) {\r
+                       RowColKey other = (RowColKey) obj;\r
+                       return _rowIndex == other._rowIndex && _columnIndex == other._columnIndex;\r
+               }\r
+               @Override\r
+               public int hashCode() {\r
+                       return _rowIndex ^ _columnIndex;\r
+               }\r
+               public int compareTo(RowColKey o) {\r
+                       int cmp = _rowIndex - o._rowIndex;\r
+                       if (cmp != 0) {\r
+                               return cmp;\r
+                       }\r
+                       return _columnIndex - o._columnIndex;\r
+               }\r
+               public int getRowIndex() {\r
+                       return _rowIndex;\r
+               }\r
+               public int getColumnIndex() {\r
+                       return _columnIndex;\r
+               }\r
+       }\r
+}\r
diff --git a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java
new file mode 100644 (file)
index 0000000..d7e158f
--- /dev/null
@@ -0,0 +1,144 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.ss.formula.eval.forked;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import org.apache.poi.hssf.record.formula.NamePtg;\r
+import org.apache.poi.hssf.record.formula.NameXPtg;\r
+import org.apache.poi.hssf.record.formula.Ptg;\r
+import org.apache.poi.ss.formula.EvaluationCell;\r
+import org.apache.poi.ss.formula.EvaluationName;\r
+import org.apache.poi.ss.formula.EvaluationSheet;\r
+import org.apache.poi.ss.formula.EvaluationWorkbook;\r
+import org.apache.poi.ss.usermodel.Workbook;\r
+\r
+/**\r
+ * Represents a workbook being used for forked evaluation. Most operations are delegated to the\r
+ * shared master workbook, except those that potentially involve cell values that may have been \r
+ * updated after a call to {@link #getOrCreateUpdatableCell(String, int, int)}.\r
+ *\r
+ * @author Josh Micich\r
+ */\r
+final class ForkedEvaluationWorkbook implements EvaluationWorkbook {\r
+\r
+       private final EvaluationWorkbook _masterBook;\r
+       private final Map<String, ForkedEvaluationSheet> _sharedSheetsByName;\r
+\r
+       public ForkedEvaluationWorkbook(EvaluationWorkbook master) {\r
+               _masterBook = master;\r
+               _sharedSheetsByName = new HashMap<String, ForkedEvaluationSheet>();\r
+       }\r
+\r
+       public ForkedEvaluationCell getOrCreateUpdatableCell(String sheetName, int rowIndex,\r
+                       int columnIndex) {\r
+               ForkedEvaluationSheet sheet = getSharedSheet(sheetName);\r
+               return sheet.getOrCreateUpdatableCell(rowIndex, columnIndex);\r
+       }\r
+\r
+       public EvaluationCell getEvaluationCell(String sheetName, int rowIndex, int columnIndex) {\r
+               ForkedEvaluationSheet sheet = getSharedSheet(sheetName);\r
+               return sheet.getCell(rowIndex, columnIndex);\r
+       }\r
+\r
+       private ForkedEvaluationSheet getSharedSheet(String sheetName) {\r
+               ForkedEvaluationSheet result = _sharedSheetsByName.get(sheetName);\r
+               if (result == null) {\r
+                       result = new ForkedEvaluationSheet(_masterBook.getSheet(_masterBook\r
+                                       .getSheetIndex(sheetName)));\r
+                       _sharedSheetsByName.put(sheetName, result);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       public void copyUpdatedCells(Workbook workbook) {\r
+               String[] sheetNames = new String[_sharedSheetsByName.size()];\r
+               _sharedSheetsByName.keySet().toArray(sheetNames);\r
+               OrderedSheet[] oss = new OrderedSheet[sheetNames.length];\r
+               for (int i = 0; i < sheetNames.length; i++) {\r
+                       String sheetName = sheetNames[i];\r
+                       oss[i] = new OrderedSheet(sheetName, _masterBook.getSheetIndex(sheetName));\r
+               }\r
+               for (int i = 0; i < oss.length; i++) {\r
+                       String sheetName = oss[i].getSheetName();\r
+                       ForkedEvaluationSheet sheet = _sharedSheetsByName.get(sheetName);\r
+                       sheet.copyUpdatedCells(workbook.getSheet(sheetName));\r
+               }\r
+       }\r
+\r
+       public int convertFromExternSheetIndex(int externSheetIndex) {\r
+               return _masterBook.convertFromExternSheetIndex(externSheetIndex);\r
+       }\r
+\r
+       public ExternalSheet getExternalSheet(int externSheetIndex) {\r
+               return _masterBook.getExternalSheet(externSheetIndex);\r
+       }\r
+\r
+       public Ptg[] getFormulaTokens(EvaluationCell cell) {\r
+               if (cell instanceof ForkedEvaluationCell) {\r
+                   // doesn't happen yet because formulas cannot be modified from the master workbook\r
+                   throw new RuntimeException("Updated formulas not supported yet");\r
+               }\r
+               return _masterBook.getFormulaTokens(cell);\r
+       }\r
+\r
+       public EvaluationName getName(NamePtg namePtg) {\r
+               return _masterBook.getName(namePtg);\r
+       }\r
+\r
+       public EvaluationSheet getSheet(int sheetIndex) {\r
+               return getSharedSheet(getSheetName(sheetIndex));\r
+       }\r
+\r
+       public int getSheetIndex(EvaluationSheet sheet) {\r
+               if (sheet instanceof ForkedEvaluationSheet) {\r
+                       ForkedEvaluationSheet mes = (ForkedEvaluationSheet) sheet;\r
+                       return mes.getSheetIndex(_masterBook);\r
+               }\r
+               return _masterBook.getSheetIndex(sheet);\r
+       }\r
+\r
+       public int getSheetIndex(String sheetName) {\r
+               return _masterBook.getSheetIndex(sheetName);\r
+       }\r
+\r
+       public String getSheetName(int sheetIndex) {\r
+               return _masterBook.getSheetName(sheetIndex);\r
+       }\r
+\r
+       public String resolveNameXText(NameXPtg ptg) {\r
+               return _masterBook.resolveNameXText(ptg);\r
+       }\r
+\r
+       private static final class OrderedSheet implements Comparable<OrderedSheet> {\r
+               private final String _sheetName;\r
+               private final int _index;\r
+\r
+               public OrderedSheet(String sheetName, int index) {\r
+                       _sheetName = sheetName;\r
+                       _index = index;\r
+               }\r
+               public String getSheetName() {\r
+                       return _sheetName;\r
+               }\r
+               public int compareTo(OrderedSheet o) {\r
+                       return _index - o._index;\r
+               }\r
+       }\r
+}\r
diff --git a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluator.java b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluator.java
new file mode 100644 (file)
index 0000000..3111dda
--- /dev/null
@@ -0,0 +1,134 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.ss.formula.eval.forked;\r
+\r
+import org.apache.poi.hssf.record.formula.eval.BoolEval;\r
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;\r
+import org.apache.poi.hssf.record.formula.eval.NumberEval;\r
+import org.apache.poi.hssf.record.formula.eval.StringEval;\r
+import org.apache.poi.hssf.record.formula.eval.ValueEval;\r
+import org.apache.poi.hssf.usermodel.HSSFCell;\r
+import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;\r
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
+import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment;\r
+import org.apache.poi.ss.formula.EvaluationCell;\r
+import org.apache.poi.ss.formula.EvaluationWorkbook;\r
+import org.apache.poi.ss.formula.IStabilityClassifier;\r
+import org.apache.poi.ss.formula.WorkbookEvaluator;\r
+import org.apache.poi.ss.usermodel.Workbook;\r
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;\r
+\r
+/**\r
+ * An alternative workbook evaluator that saves memory in situations where a single workbook is\r
+ * concurrently and independently evaluated many times.  With standard formula evaluation, around \r
+ * 90% of memory consumption is due to loading of the {@link HSSFWorkbook} or {@link XSSFWorkbook}.\r
+ * This class enables a 'master workbook' to be loaded just once and shared between many evaluation\r
+ * clients.  Each evaluation client creates its own {@link ForkedEvaluator} and can set cell values\r
+ * that will be used for local evaluations (and don't disturb evaluations on other evaluators).\r
+ *\r
+ * @author Josh Micich\r
+ */\r
+public final class ForkedEvaluator {\r
+\r
+       private WorkbookEvaluator _evaluator;\r
+       private ForkedEvaluationWorkbook _sewb;\r
+\r
+       private ForkedEvaluator(EvaluationWorkbook masterWorkbook, IStabilityClassifier stabilityClassifier) {\r
+               _sewb = new ForkedEvaluationWorkbook(masterWorkbook);\r
+               _evaluator = new WorkbookEvaluator(_sewb, stabilityClassifier);\r
+       }\r
+       private static EvaluationWorkbook createEvaluationWorkbook(Workbook wb) {\r
+               if (wb instanceof HSSFWorkbook) {\r
+                       return HSSFEvaluationWorkbook.create((HSSFWorkbook) wb);\r
+               }\r
+// TODO rearrange POI build to allow this\r
+//             if (wb instanceof XSSFWorkbook) {\r
+//                     return XSSFEvaluationWorkbook.create((XSSFWorkbook) wb);\r
+//             }\r
+               throw new IllegalArgumentException("Unexpected workbook type (" + wb.getClass().getName() + ")");\r
+       }\r
+       public static ForkedEvaluator create(Workbook wb, IStabilityClassifier stabilityClassifier) {\r
+               return new ForkedEvaluator(createEvaluationWorkbook(wb), stabilityClassifier);\r
+       }\r
+\r
+       /**\r
+        * Sets the specified cell to the supplied <tt>value</tt>\r
+        * @param sheetName the name of the sheet containing the cell\r
+        * @param rowIndex zero based\r
+        * @param columnIndex zero based\r
+        */\r
+       public void updateCell(String sheetName, int rowIndex, int columnIndex, ValueEval value) {\r
+\r
+               ForkedEvaluationCell cell = _sewb.getOrCreateUpdatableCell(sheetName, rowIndex, columnIndex);\r
+               cell.setValue(value);\r
+               _evaluator.notifyUpdateCell(cell);\r
+       }\r
+       /**\r
+        * Copies the values of all updated cells (modified by calls to {@link \r
+        * #updateCell(String, int, int, ValueEval)}) to the supplied <tt>workbook</tt>.<br/>\r
+        * Typically, the supplied <tt>workbook</tt> is a writable copy of the 'master workbook', \r
+        * but at the very least it must contain sheets with the same names. \r
+        */\r
+       public void copyUpdatedCells(Workbook workbook) {\r
+               _sewb.copyUpdatedCells(workbook);\r
+       }\r
+\r
+       /**\r
+        * If cell contains a formula, the formula is evaluated and returned,\r
+        * else the CellValue simply copies the appropriate cell value from\r
+        * the cell and also its cell type. This method should be preferred over\r
+        * evaluateInCell() when the call should not modify the contents of the\r
+        * original cell.\r
+        *\r
+        * @param cell may be <code>null</code> signifying that the cell is not present (or blank)\r
+        * @return <code>null</code> if the supplied cell is <code>null</code> or blank\r
+        */\r
+       public ValueEval evaluate(String sheetName, int rowIndex, int columnIndex) {\r
+               EvaluationCell cell = _sewb.getEvaluationCell(sheetName, rowIndex, columnIndex);\r
+\r
+               switch (cell.getCellType()) {\r
+                       case HSSFCell.CELL_TYPE_BOOLEAN:\r
+                               return BoolEval.valueOf(cell.getBooleanCellValue());\r
+                       case HSSFCell.CELL_TYPE_ERROR:\r
+                               return ErrorEval.valueOf(cell.getErrorCellValue());\r
+                       case HSSFCell.CELL_TYPE_FORMULA:\r
+                               return _evaluator.evaluate(cell);\r
+                       case HSSFCell.CELL_TYPE_NUMERIC:\r
+                               return new NumberEval(cell.getNumericCellValue());\r
+                       case HSSFCell.CELL_TYPE_STRING:\r
+                               return new StringEval(cell.getStringCellValue());\r
+                       case HSSFCell.CELL_TYPE_BLANK:\r
+                               return null;\r
+               }\r
+               throw new IllegalStateException("Bad cell type (" + cell.getCellType() + ")");\r
+       }\r
+       /**\r
+        * Coordinates several formula evaluators together so that formulas that involve external\r
+        * references can be evaluated.\r
+        * @param workbookNames the simple file names used to identify the workbooks in formulas\r
+        * with external links (for example "MyData.xls" as used in a formula "[MyData.xls]Sheet1!A1")\r
+        * @param evaluators all evaluators for the full set of workbooks required by the formulas.\r
+        */\r
+       public static void setupEnvironment(String[] workbookNames, ForkedEvaluator[] evaluators) {\r
+               WorkbookEvaluator[] wbEvals = new WorkbookEvaluator[evaluators.length];\r
+               for (int i = 0; i < wbEvals.length; i++) {\r
+                       wbEvals[i] = evaluators[i]._evaluator;\r
+               }\r
+               CollaboratingWorkbooksEnvironment.setup(workbookNames, wbEvals);\r
+       }\r
+}\r