/**
* OpenSpotLight - Open Source IT Governance Platform
*
* Copyright (c) 2009, CARAVELATECH CONSULTORIA E TECNOLOGIA EM INFORMATICA LTDA
* or third-party contributors as indicated by the @author tags or express
* copyright attribution statements applied by the authors. All third-party
* contributions are distributed under license by CARAVELATECH CONSULTORIA E
* TECNOLOGIA EM INFORMATICA LTDA.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
***********************************************************************
* OpenSpotLight - Plataforma de Governança de TI de Código Aberto
*
* Direitos Autorais Reservados (c) 2009, CARAVELATECH CONSULTORIA E TECNOLOGIA
* EM INFORMATICA LTDA ou como contribuidores terceiros indicados pela etiqueta
* @author ou por expressa atribuição de direito autoral declarada e atribuída pelo autor.
* Todas as contribuições de terceiros estão distribuídas sob licença da
* CARAVELATECH CONSULTORIA E TECNOLOGIA EM INFORMATICA LTDA.
*
* Este programa é software livre; você pode redistribuí-lo e/ou modificá-lo sob os
* termos da Licença Pública Geral Menor do GNU conforme publicada pela Free Software
* Foundation.
*
* Este programa é distribuído na expectativa de que seja útil, porém, SEM NENHUMA
* GARANTIA; nem mesmo a garantia implícita de COMERCIABILIDADE OU ADEQUAÇÃO A UMA
* FINALIDADE ESPECÍFICA. Consulte a Licença Pública Geral Menor do GNU para mais detalhes.
*
* Você deve ter recebido uma cópia da Licença Pública Geral Menor do GNU junto com este
* programa; se não, escreva para:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.openspotlight.federation.finder.db;
import static java.text.MessageFormat.format;
import static org.openspotlight.common.util.Arrays.andOf;
import static org.openspotlight.common.util.Arrays.of;
import static org.openspotlight.common.util.ClassPathResource.getResourceFromClassPath;
import static org.openspotlight.common.util.Equals.eachEquality;
import static org.openspotlight.common.util.Exceptions.logAndReturn;
import static org.openspotlight.common.util.Exceptions.logAndReturnNew;
import static org.openspotlight.common.util.HashCodes.hashOf;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import org.openspotlight.common.exception.ConfigurationException;
import org.openspotlight.federation.domain.artifact.db.DatabaseType;
import org.openspotlight.federation.finder.db.DatabaseMetadataScript.PreferedType;
import com.thoughtworks.xstream.XStream;
/**
* Singleton for guarding the database metadata scripts, and to load this only once or when asked. The xml with all select
* statments to get the metadata is stored on a private static final field inside this class. This script metadata information
* could be on the same structure as we have the configuration metadata for instance. The reason that it is not that way is that
* this metadata information from databases should be common for all instalations of OSL. It's not a instalation specific
* information. So, it needs to be on classpath instead of a file, and of course it wont go to the Jcr metadata repository.
*
* @author Luiz Fernando Teston - feu.teston@caravelatech.com
*/
public enum DatabaseMetadataScriptManager {
/**
* Single instance.
*/
INSTANCE;
private static class MapKey {
private final DatabaseType databaseType;
private final int hashCode;
private final ScriptType scriptType;
public MapKey(
final DatabaseType databaseType, final ScriptType scriptType) {
this.databaseType = databaseType;
this.scriptType = scriptType;
hashCode = hashOf(databaseType, scriptType);
}
@Override
public boolean equals(final Object o) {
if (o == this) { return true; }
if (!(o instanceof MapKey)) { return false; }
final MapKey that = (MapKey) o;
return eachEquality(of(databaseType, scriptType), andOf(that.databaseType, that.scriptType));
}
@Override
public int hashCode() {
return hashCode;
}
}
private final Map<MapKey, DatabaseMetadataScript> scriptMap = new HashMap<MapKey, DatabaseMetadataScript>();
/**
* Load the {@link DatabaseMetadataScripts} if needed and return the loaded script metadata.
*
* @param databaseType
* @param scriptType
* @return the database metadata script or null if there's no script for that db and type
*/
public DatabaseMetadataScript getScript(final DatabaseType databaseType,
final ScriptType scriptType) {
if (scriptMap.size() == 0) {
reloadScripts();
}
DatabaseMetadataScript script = scriptMap.get(new MapKey(databaseType, scriptType));
DatabaseType internalType = databaseType;
while (script == null) {
internalType = internalType.getParent();
if (internalType == null) { return null; }
script = scriptMap.get(new MapKey(internalType, scriptType));
}
return script;
}
/**
* Force the scripts reload. Should no be called in a common way, since the configuration file stays on classpath.
*
* @throws ConfigurationException
*/
public synchronized void reloadScripts()
throws ConfigurationException {
try {
scriptMap.clear();
final XStream xstream = new XStream();
xstream.alias("script", DatabaseMetadataScript.class); //$NON-NLS-1$
xstream.alias("column", ColumnsNamesForMetadataSelect.class);//$NON-NLS-1$
xstream.omitField(DatabaseMetadataScript.class, "immutable"); //$NON-NLS-1$
for (final ScriptType scriptType: ScriptType.values()) {
for (final DatabaseType databaseType: DatabaseType.values()) {
final String fileName = format("/configuration/{0}-{1}.xml", databaseType, scriptType);
final InputStream stream = getResourceFromClassPath(fileName);
if (stream == null) {
continue;
}
final DatabaseMetadataScript newScript = (DatabaseMetadataScript) xstream.fromXML(stream);
if (!databaseType.equals(newScript.getDatabase())) {
logAndReturn(new IllegalStateException(format("Wrong database on {0}", fileName)));
}
if (!scriptType.equals(newScript.getScriptType())) {
logAndReturn(new IllegalStateException(format("Wrong scriptType on {0}", fileName)));
}
if (newScript.getPreferedType() == null) {
logAndReturn(new IllegalStateException(format("No preferedType on {0}", fileName)));
}
if (PreferedType.SQL.equals(newScript.getPreferedType())
&& ((newScript.getContentSelect() == null) || (newScript.getDataSelect() == null))) {
logAndReturn(new IllegalStateException(
format(
"PreferedType SQL but no selects for content or data on {0}",
fileName)));
}
if (PreferedType.TEMPLATE.equals(newScript.getPreferedType())
&& ((newScript.getTemplate() == null) || (newScript.getTemplatesSelect() == null))) {
logAndReturn(new IllegalStateException(
format(
"PreferedType TEMPLATE but no select for template or missing template itself on {0}",
fileName)));
}
scriptMap.put(new MapKey(newScript.getDatabase(), newScript.getScriptType()), newScript);
}
}
} catch (final Exception e) {
throw logAndReturnNew(e, ConfigurationException.class);
}
}
}