/*******************************************************************************
*
* 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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.netxilia.api.INetxiliaSystem;
import org.netxilia.api.command.IMoreCellCommands;
import org.netxilia.api.display.IStyleService;
import org.netxilia.api.exception.AlreadyExistsException;
import org.netxilia.api.exception.NotFoundException;
import org.netxilia.api.exception.StorageException;
import org.netxilia.api.formula.IPreloadedFormulaContextFactory;
import org.netxilia.api.impl.model.SheetNames;
import org.netxilia.api.impl.model.Workbook;
import org.netxilia.api.impl.user.ISpringUserService;
import org.netxilia.api.model.ISheet;
import org.netxilia.api.model.IWorkbook;
import org.netxilia.api.model.SheetData;
import org.netxilia.api.model.SheetFullName;
import org.netxilia.api.model.WorkbookId;
import org.netxilia.api.storage.DataSourceConfigurationId;
import org.netxilia.api.user.AclPrivilegedMode;
import org.netxilia.api.user.IAclService;
import org.netxilia.api.user.IUserService;
import org.netxilia.api.user.Permission;
import org.netxilia.api.value.IGenericValueParseService;
import org.netxilia.spi.formula.IFormulaCalculatorFactory;
import org.netxilia.spi.formula.IFormulaParser;
import org.netxilia.spi.storage.IWorkbookStorageService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* This class is the core of the Netxilia sheet system. It allows client code access to the sheets and manages events
* occured after a sheet was modified.
*
* @author <a href='mailto:ax.craciun@gmail.com'>Alexandru Craciun</a>
*
*/
public class NetxiliaSystemImpl implements INetxiliaSystem {
private static org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(NetxiliaSystemImpl.class);
@Autowired
private IWorkbookStorageService storageService;
@Autowired
private IFormulaParser formulaParser;
private final Map<WorkbookId, Workbook> workbooks = new HashMap<WorkbookId, Workbook>();
@Autowired
private IStyleService styleService;
@Autowired
private IAclService aclService;
@Autowired
private IUserService userService;
@Autowired
private IGenericValueParseService parseService;
@Autowired
private ISpringUserService springUserService;
@Autowired
private IFormulaCalculatorFactory formulaCalculatorFactory;
@Autowired
private IExecutorServiceFactory executorServiceFactory;
@Autowired
private IMoreCellCommands moreCellCommands;
@Autowired
private IPreloadedFormulaContextFactory preloadContextFactory;
private boolean sheetInitializationEnabled = true;
public NetxiliaSystemImpl() {
}
public IWorkbookStorageService getStorageService() {
return storageService;
}
public void setStorageService(IWorkbookStorageService storageService) {
this.storageService = storageService;
}
public IMoreCellCommands getMoreCellCommands() {
return moreCellCommands;
}
public void setMoreCellCommands(IMoreCellCommands moreCellCommands) {
this.moreCellCommands = moreCellCommands;
}
public IPreloadedFormulaContextFactory getPreloadContextFactory() {
return preloadContextFactory;
}
public void setPreloadContextFactory(IPreloadedFormulaContextFactory preloadContextFactory) {
this.preloadContextFactory = preloadContextFactory;
}
public IExecutorServiceFactory getExecutorServiceFactory() {
return executorServiceFactory;
}
public void setExecutorServiceFactory(IExecutorServiceFactory executorServiceFactory) {
this.executorServiceFactory = executorServiceFactory;
}
public IFormulaParser getFormulaParser() {
return formulaParser;
}
public void setFormulaParser(IFormulaParser formulaParser) {
this.formulaParser = formulaParser;
}
public IStyleService getStyleService() {
return styleService;
}
public void setStyleService(IStyleService styleService) {
this.styleService = styleService;
}
public IAclService getAclService() {
return aclService;
}
public void setAclService(IAclService aclService) {
this.aclService = aclService;
}
public IUserService getUserService() {
return userService;
}
public void setUserService(IUserService userService) {
this.userService = userService;
}
public ISpringUserService getSpringUserService() {
return springUserService;
}
public void setSpringUserService(ISpringUserService springUserService) {
this.springUserService = springUserService;
}
public IGenericValueParseService getParseService() {
return parseService;
}
public void setParseService(IGenericValueParseService parseService) {
this.parseService = parseService;
}
public IFormulaCalculatorFactory getFormulaCalculatorFactory() {
return formulaCalculatorFactory;
}
public void setFormulaCalculatorFactory(IFormulaCalculatorFactory formulaCalculatorFactory) {
this.formulaCalculatorFactory = formulaCalculatorFactory;
}
@Override
public Workbook getWorkbook(WorkbookId workbookId) throws StorageException, NotFoundException {
aclService.checkPermission(workbookId, Permission.read);
synchronized (workbooks) {
// TODO increase concurrency here
Workbook workbook = workbooks.get(workbookId);
if (workbook == null) {
List<SheetData> sheets = storageService.loadSheets(workbookId);
workbook = Workbook.newInstance(this, workbookId, sheets);
if (workbook == null) {
throw new NotFoundException("Could not load the workbook");
}
workbooks.put(workbookId, workbook);
}
return workbook;
}
}
public void deleteWorkbook(WorkbookId workbookId) throws StorageException, NotFoundException {
boolean wasSet = AclPrivilegedMode.set();
synchronized (workbooks) {
try {
// delete all the sheets one after the other in privileged mode
Workbook workbook = getWorkbook(workbookId);
// make a copy of the list as the collection is altered when deleting a sheet
Collection<ISheet> copySheets = new ArrayList<ISheet>(workbook.getSheets());
for (ISheet sheet : copySheets) {
workbook.deleteSheet(sheet);
}
storageService.deleteWorkbook(workbookId);
workbooks.remove(workbookId.getKey());
} finally {
if (!wasSet) {
AclPrivilegedMode.clear();
}
}
}
}
@Override
public IWorkbook addNewWorkbook(DataSourceConfigurationId dataSourceConfigId, WorkbookId workbookId)
throws StorageException, NotFoundException, AlreadyExistsException {
boolean wasSet = AclPrivilegedMode.set();
IWorkbook workbook = null;
synchronized (workbooks) {
try {
if (workbooks.get(workbookId) != null) {
throw new AlreadyExistsException();
}
workbook = storageService.add(dataSourceConfigId, workbookId);
workbooks.put(workbookId, (Workbook) workbook);
aclService.setPermissions(workbookId, null, Permission.read, Permission.write);
aclService.setPermissions(new SheetFullName(workbookId, SheetNames.PERMISSIONS), null, Permission.read,
Permission.write);
} finally {
if (!wasSet) {
AclPrivilegedMode.clear();
}
}
}
return workbook;
}
public void close() {
log.info("Closing workbook processor");
workbooks.clear();
}
public boolean isSheetInitializationEnabled() {
return sheetInitializationEnabled;
}
public void setSheetInitializationEnabled(boolean sheetInitializationEnabled) {
this.sheetInitializationEnabled = sheetInitializationEnabled;
}
}