/******************************************************************************* * * Copyright 2010 Alexandru Craciun, and individual contributors as indicated * by the @authors tag. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 3 of * the License, or (at your option) any later version. * * This software 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 GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. ******************************************************************************/ package org.netxilia.api.impl.dependencies; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.netxilia.api.command.IMoreCellCommands; import org.netxilia.api.event.IWorkbookEventListener; import org.netxilia.api.event.SheetEvent; import org.netxilia.api.exception.NotFoundException; import org.netxilia.api.exception.StorageException; import org.netxilia.api.formula.CyclicDependenciesException; import org.netxilia.api.formula.Formula; import org.netxilia.api.formula.IFormulaContext; import org.netxilia.api.model.ISheet; import org.netxilia.api.model.IWorkbook; import org.netxilia.api.reference.AreaReference; import org.netxilia.api.reference.CellReference; import org.netxilia.spi.formula.IFormulaParser; import org.springframework.util.Assert; /** * This class coordinates the dependency between cells in different sheets. It contains a map of * {@link SheetDependencyManager} * * @author <a href='mailto:ax.craciun@gmail.com'>Alexandru Craciun</a> * */ public class WorkbookDependencyManager implements IDependencyManager, IWorkbookEventListener { private static org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(WorkbookDependencyManager.class); private final ConcurrentMap<String, SheetDependencyManager> cellDependencyManagers = new ConcurrentHashMap<String, SheetDependencyManager>(); private final IWorkbook workbook; private final IMoreCellCommands moreCellCommands; private final IFormulaParser formulaParser; private WorkbookDependencyManager(IWorkbook workbook, IMoreCellCommands moreCellCommands, IFormulaParser formulaParser) { this.workbook = workbook; this.moreCellCommands = moreCellCommands; this.formulaParser = formulaParser; } public IWorkbook getWorkbook() { return workbook; } @Override public List<AreaReference> getDependencies(CellReference ref) { if (ref.getSheetName() == null) { throw new IllegalArgumentException("Sheet name is not specified for this reference:" + ref); } SheetDependencyManager mgr = cellDependencyManagers.get(ref.getSheetName()); if (mgr == null) { return Collections.emptyList(); } return mgr.getDependencies(ref); } @Override public List<CellReference> getAllInverseDependencies(CellReference ref) { if (ref.getSheetName() == null) { throw new IllegalArgumentException("Sheet name is not specified for this reference:" + ref); } SheetDependencyManager mgr = cellDependencyManagers.get(ref.getSheetName()); if (mgr == null) { return Collections.emptyList(); } return mgr.getAllInverseDependencies(ref); } public SheetDependencyManager getManagerForSheet(String sheetName) throws StorageException, NotFoundException { SheetDependencyManager mgr = cellDependencyManagers.get(sheetName); if (mgr == null) { ISheet sheet = workbook.getSheet(sheetName); SheetDependencyManager newMgr = SheetDependencyManager.newInstance(this, sheet, moreCellCommands, formulaParser); mgr = cellDependencyManagers.putIfAbsent(sheetName, newMgr); if (mgr == null) { mgr = newMgr; } } return mgr; } public void setDependencies(Formula formula, IFormulaContext context) throws CyclicDependenciesException, StorageException, NotFoundException { CellReference ref = context.getCell(); if (ref.getSheetName() == null) { throw new IllegalArgumentException("Sheet name is not specified for this reference:" + ref); } getManagerForSheet(ref.getSheetName()).setDependencies(formula, context); } public Set<AreaReference> deleteSheet(String sheetName) { SheetDependencyManager mgr = cellDependencyManagers.get(sheetName); if (mgr != null) { Set<AreaReference> affectedAreas = mgr.deleteSheet(); cellDependencyManagers.remove(sheetName); return affectedAreas; } return Collections.emptySet(); } @Override public void onDeletedSheet(SheetEvent sheetEvent) { deleteSheet(sheetEvent.getSheetName().getSheetName()); } @Override public void onNewSheet(SheetEvent sheetEvent) { try { getManagerForSheet(sheetEvent.getSheetName().getSheetName()); } catch (StorageException e) { log.error("Could not register depedency manager for sheet: " + sheetEvent.getSheetName() + ":" + e, e); } catch (NotFoundException e) { log.error("Could not register depedency manager for sheet: " + sheetEvent.getSheetName() + ":" + e, e); } } public static WorkbookDependencyManager newInstance(IWorkbook workbook, IMoreCellCommands moreCellCommands, IFormulaParser formulaParser) { Assert.notNull(workbook); Assert.notNull(moreCellCommands); Assert.notNull(formulaParser); WorkbookDependencyManager manager = new WorkbookDependencyManager(workbook, moreCellCommands, formulaParser); manager.workbook.addListener(manager); // add a listener for all existing sheets for (ISheet sheet : workbook.getSheets()) { try { manager.getManagerForSheet(sheet.getName()); } catch (StorageException e) { log.error("Could not register depedency manager for sheet: " + sheet.getName() + ":" + e, e); } catch (NotFoundException e) { log.error("Could not register depedency manager for sheet: " + sheet.getName() + ":" + e, e); } } return manager; } }