package org.pentaho.reporting.engine.classic.core.modules.misc.connections;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.database.model.IDatabaseConnection;
import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot;
import org.pentaho.reporting.engine.classic.core.modules.misc.connections.parser.DatabaseConnectionCollection;
import org.pentaho.reporting.engine.classic.core.modules.misc.connections.writer.DataSourceMgmtWriter;
import org.pentaho.reporting.engine.classic.core.util.ConfigurationPropertyLookupParser;
import org.pentaho.reporting.libraries.base.boot.SingletonHint;
import org.pentaho.reporting.libraries.base.config.Configuration;
import org.pentaho.reporting.libraries.resourceloader.Resource;
import org.pentaho.reporting.libraries.resourceloader.ResourceException;
import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
@SuppressWarnings("HardCodedStringLiteral")
@SingletonHint
public class FileDataSourceMgmtService implements DataSourceMgmtService
{
private static final Log logger = LogFactory.getLog(FileDataSourceMgmtService.class);
private HashMap<String, SerializedConnection> connectionsByName;
private HashMap<String, SerializedConnection> connectionsById;
private File target;
private long lastModifiedDate;
public FileDataSourceMgmtService()
{
connectionsById = new HashMap<String, SerializedConnection>();
connectionsByName = new HashMap<String, SerializedConnection>();
lastModifiedDate = -1;
}
protected File createTargetFile()
{
final Configuration globalConfig = ClassicEngineBoot.getInstance().getGlobalConfig();
final ConfigurationPropertyLookupParser parser = new ConfigurationPropertyLookupParser(globalConfig);
final String fileName = parser.translateAndLookup(globalConfig.getConfigProperty
("org.pentaho.reporting.engine.classic.core.modules.misc.connections.file-data.targetLocation"));
final File file = new File(fileName);
file.getParentFile().mkdirs();
return file;
}
public File getTarget()
{
return target;
}
public void setTarget(final File target)
{
this.target = target;
}
public synchronized String createDatasource(final IDatabaseConnection databaseConnection)
throws DuplicateDatasourceException, DatasourceMgmtServiceException
{
load();
String name = databaseConnection.getName();
if (name == null)
{
name = generateName();
}
if (connectionsByName.containsKey(name))
{
throw new DuplicateDatasourceException();
}
final String id = UUID.randomUUID().toString();
databaseConnection.setId(id);
databaseConnection.setName(name);
final SerializedConnection serializedConnection = new SerializedConnection(databaseConnection);
connectionsById.put(id, serializedConnection);
connectionsByName.put(name, serializedConnection);
writeChanges();
return id;
}
private String generateName()
{
// todo: Maybe we can have a better strategy here later
return UUID.randomUUID().toString();
}
public synchronized void deleteDatasourceById(final String id) throws NonExistingDatasourceException, DatasourceMgmtServiceException
{
load();
final SerializedConnection connection = connectionsById.get(id);
if (connection == null)
{
throw new NonExistingDatasourceException();
}
final IDatabaseConnection databaseConnection = connection.getConnection();
connectionsByName.remove(databaseConnection.getName());
connectionsById.remove(databaseConnection.getId());
writeChanges();
}
public IDatabaseConnection getDatasourceByName(final String name) throws DatasourceMgmtServiceException
{
load();
final SerializedConnection connection = connectionsByName.get(name);
if (connection == null)
{
throw new NonExistingDatasourceException();
}
return connection.getConnection();
}
public IDatabaseConnection getDatasourceById(final String id) throws DatasourceMgmtServiceException
{
load();
final SerializedConnection connection = connectionsById.get(id);
if (connection == null)
{
throw new NonExistingDatasourceException();
}
return connection.getConnection();
}
public List<IDatabaseConnection> getDatasources() throws DatasourceMgmtServiceException
{
load();
final ArrayList<IDatabaseConnection> connections = new ArrayList<IDatabaseConnection>();
final Collection<SerializedConnection> values = connectionsById.values();
for (final SerializedConnection co : values)
{
connections.add(co.getConnection());
}
return connections;
}
public List<String> getDatasourceIds() throws DatasourceMgmtServiceException
{
load();
final ArrayList<String> connections = new ArrayList<String>();
final Collection<SerializedConnection> values = connectionsById.values();
for (final SerializedConnection co : values)
{
connections.add(co.getConnection().getId());
}
return connections;
}
public String updateDatasourceById(final String id,
final IDatabaseConnection databaseConnection)
throws NonExistingDatasourceException, DatasourceMgmtServiceException
{
load();
final SerializedConnection connection = connectionsById.get(id);
if (connection == null)
{
throw new NonExistingDatasourceException();
}
final String name = connection.getConnection().getName();
databaseConnection.setId(id);
final SerializedConnection serializedConnection = new SerializedConnection(databaseConnection);
connectionsById.put(id, serializedConnection);
connectionsByName.remove(name);
connectionsByName.put(serializedConnection.getConnection().getName(), serializedConnection);
writeChanges();
return id;
}
protected void load()
{
if (target == null)
{
target = createTargetFile();
}
if (target == null)
{
return;
}
if (target.lastModified() == lastModifiedDate)
{
return;
}
synchronized (this)
{
try
{
final ResourceManager mgr = new ResourceManager();
mgr.registerDefaults();
final ResourceKey key = mgr.createKey(target);
final Resource resource = mgr.create(key, null, DatabaseConnectionCollection.class);
final DatabaseConnectionCollection collection = (DatabaseConnectionCollection) resource.getResource();
for (final IDatabaseConnection connection : collection.getConnections())
{
final String id = connection.getId();
final String name = connection.getName();
if (name == null)
{
logger.warn("Skipping invalid connection definition, name is empty.");
continue;
}
if (id == null)
{
logger.warn("Skipping invalid connection definition, id is empty.");
continue;
}
final SerializedConnection value = new SerializedConnection(connection);
connectionsById.put(id, value);
connectionsByName.put(name, value);
}
}
catch (ResourceException e)
{
logger.error("Unable to parse datasource declaration.", e);
}
catch (IOException e)
{
logger.error("Unable to parse datasource declaration.", e);
}
finally
{
lastModifiedDate = target.lastModified();
}
}
}
protected void writeChanges()
{
final List<IDatabaseConnection> datasources = getDatasources();
final IDatabaseConnection[] connections = datasources.toArray(new IDatabaseConnection[datasources.size()]);
final DataSourceMgmtWriter writer =
ClassicEngineBoot.getInstance().getObjectFactory().get(DataSourceMgmtWriter.class);
try
{
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
writer.write(connections, bout);
if (target == null)
{
target = createTargetFile();
}
if (target == null)
{
return;
}
final FileOutputStream fout = new FileOutputStream(target);
try
{
fout.write(bout.toByteArray());
}
finally
{
fout.close();
}
}
catch (IOException e)
{
logger.error("Unable to write datasource declaration.", e);
}
}
}