package org.pentaho.reporting.engine.classic.core.modules.misc.connections;
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;
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;
@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;
}
if ( !target.exists() ) {
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 ) {
if ( logger.isDebugEnabled() ) {
logger.error( "Unable to parse datasource declaration.", e );
} else {
logger.error( "Unable to parse datasource declaration: " + e );
}
} catch ( IOException e ) {
if ( logger.isDebugEnabled() ) {
logger.error( "Unable to parse datasource declaration.", e );
} else {
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 );
}
}
}