strolch/persistence-xml/src/main/java/li/strolch/persistence/xml/XmlPersistenceHandler.java

242 lines
9.2 KiB
Java

/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.persistence.xml;
import static li.strolch.agent.impl.DefaultRealmHandler.PREFIX_DATA_STORE_FILE;
import static li.strolch.db.DbConstants.PROP_DB_IGNORE_REALM;
import static li.strolch.db.DbConstants.PROP_USE_ENV;
import static li.strolch.runtime.StrolchConstants.makeRealmKey;
import static li.strolch.utils.helper.StringHelper.isEmpty;
import java.io.File;
import java.text.MessageFormat;
import java.util.*;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.RealmHandler;
import li.strolch.agent.api.StrolchComponent;
import li.strolch.agent.api.StrolchRealm;
import li.strolch.agent.impl.StoreToDaoElementListener;
import li.strolch.model.ModelStatistics;
import li.strolch.model.Order;
import li.strolch.model.Resource;
import li.strolch.model.Tags;
import li.strolch.model.activity.Activity;
import li.strolch.model.audit.Audit;
import li.strolch.model.log.LogMessage;
import li.strolch.model.xml.XmlModelSaxFileReader;
import li.strolch.persistence.api.*;
import li.strolch.persistence.xml.model.*;
import li.strolch.privilege.model.Certificate;
import li.strolch.runtime.configuration.ComponentConfiguration;
import li.strolch.runtime.configuration.RuntimeConfiguration;
import li.strolch.runtime.configuration.StrolchConfiguration;
import li.strolch.runtime.configuration.StrolchConfigurationException;
import li.strolch.utils.helper.StringHelper;
import li.strolch.xmlpers.api.*;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class XmlPersistenceHandler extends StrolchComponent implements PersistenceHandler {
public static final String PROP_DB_STORE_PATH = "dbStorePath";
public static final String PROP_DB_IGNORE_REALM = "ignoreRealm"; //$NON-NLS-1$
public static final String PROP_ALLOW_DATA_INIT_ON_EMPTY_DB = "allowDataInitOnEmptyDb";
public static final String PROP_VERBOSE = "verbose"; //$NON-NLS-1$
private Map<String, PersistenceStore> persistenceStoreMap;
public XmlPersistenceHandler(ComponentContainer container, String componentName) {
super(container, componentName);
}
@Override
public boolean supportsPaging() {
return false;
}
@Override
public void initialize(ComponentConfiguration configuration) throws Exception {
this.persistenceStoreMap = new HashMap<>();
Set<String> dbStorePaths = new HashSet<>();
Set<String> realmNames = getContainer().getRealmNames();
for (String realmName : realmNames) {
StrolchRealm realm = getContainer().getRealm(realmName);
if (realm.getMode().isTransient())
continue;
String dbUseEnvKey = makeRealmKey(realmName, PROP_USE_ENV, false);
boolean dbUseEnv = configuration.getBoolean(dbUseEnvKey, false);
String dbStorePathKey = makeRealmKey(realmName, PROP_DB_STORE_PATH, dbUseEnv);
String dbVerboseKey = makeRealmKey(realmName, PROP_VERBOSE, dbUseEnv);
String dbIgnoreRealmKey = makeRealmKey(realmName, PROP_DB_IGNORE_REALM, false);
boolean dbIgnoreRealm = configuration.getBoolean(dbIgnoreRealmKey, false);
if (dbIgnoreRealm) {
logger.info("Ignoring any DB configuration for Realm " + realmName);
continue;
}
String dbStorePath = getConfigString(configuration, dbStorePathKey, dbUseEnv);
boolean verbose = getConfigBoolean(configuration, dbVerboseKey, dbUseEnv);
// validate URL
if (dbStorePaths.contains(dbStorePath))
throw new IllegalStateException(
"The " + PROP_DB_STORE_PATH + " " + dbStorePath + " is already used by another realm!");
dbStorePaths.add(dbStorePath);
File basePathF = configuration.getRuntimeConfiguration().getDataPath();
File dbStorePathF = new File(basePathF, dbStorePath);
if (!dbStorePathF.exists() && !dbStorePathF.mkdir()) {
throw new StrolchConfigurationException(
"Could not create store path at " + dbStorePathF.getAbsolutePath());
}
// build a PersistenceManager
Properties properties = new Properties();
properties.setProperty(PersistenceConstants.PROP_VERBOSE, Boolean.toString(verbose));
properties.setProperty(PersistenceConstants.PROP_XML_IO_MOD, IoMode.SAX.name());
properties.setProperty(PersistenceConstants.PROP_BASEPATH, dbStorePathF.getAbsolutePath());
PersistenceManager persistenceManager = PersistenceManagerLoader.load(properties);
PersistenceContextFactoryDelegator ctxFactory = persistenceManager.getCtxFactory();
ctxFactory.registerPersistenceContextFactory(Resource.class, Tags.RESOURCE, new ResourceContextFactory());
ctxFactory.registerPersistenceContextFactory(Order.class, Tags.ORDER, new OrderContextFactory());
ctxFactory.registerPersistenceContextFactory(Audit.class, Tags.AUDIT, new AuditContextFactory());
ctxFactory.registerPersistenceContextFactory(Activity.class, Tags.ACTIVITY, new ActivityContextFactory());
ctxFactory.registerPersistenceContextFactory(LogMessage.class, Tags.LOG_MESSAGE,
new LogMessageContextFactory());
PersistenceStore persistenceStore = new PersistenceStore();
persistenceStore.dbStorePathF = dbStorePathF;
persistenceStore.persistenceManager = persistenceManager;
this.persistenceStoreMap.put(realmName, persistenceStore);
}
super.initialize(configuration);
}
private String getConfigString(ComponentConfiguration configuration, String dbKey, boolean useEnv) {
if (!useEnv)
return configuration.getString(dbKey, null);
String value = System.getenv(dbKey);
if (isEmpty(value))
throw new IllegalStateException("Missing environment variable " + dbKey);
return value;
}
private Boolean getConfigBoolean(ComponentConfiguration configuration, String dbKey, boolean useEnv) {
if (!useEnv)
return configuration.getBoolean(dbKey, false);
String value = System.getenv(dbKey);
if (isEmpty(value))
throw new IllegalStateException("Missing environment variable " + dbKey);
return StringHelper.parseBoolean(value);
}
@Override
public void start() throws Exception {
for (String realmName : this.persistenceStoreMap.keySet()) {
String allowDataInitOnEmptyDbKey = makeRealmKey(realmName, PROP_ALLOW_DATA_INIT_ON_EMPTY_DB);
boolean allowDataInitOnEmptyDb = getConfiguration().getBoolean(allowDataInitOnEmptyDbKey, Boolean.FALSE);
PersistenceStore persistenceStore = this.persistenceStoreMap.get(realmName);
File[] files = persistenceStore.dbStorePathF.listFiles();
if (files == null)
throw new IllegalStateException(persistenceStore.dbStorePathF.getAbsolutePath() + " does not exist!");
if (files.length == 0 && allowDataInitOnEmptyDb) {
logger.info("Initializing realm " + realmName + " as DB is empty.");
StrolchConfiguration strolchConfiguration = getContainer().getAgent().getStrolchConfiguration();
ComponentConfiguration realmConfiguration = strolchConfiguration.getComponentConfiguration(
RealmHandler.class.getSimpleName());
String dataStoreKey = makeRealmKey(realmName, PREFIX_DATA_STORE_FILE);
RuntimeConfiguration runtimeConfiguration = strolchConfiguration.getRuntimeConfiguration();
File dataStoreF = realmConfiguration.getDataFile(dataStoreKey, null, runtimeConfiguration, true);
runAsAgent(ctx -> {
ModelStatistics statistics;
try (StrolchTransaction tx = openTx(getContainer().getRealm(realmName), ctx.getCertificate(),
getClass().getSimpleName(), false)) {
StoreToDaoElementListener listener = new StoreToDaoElementListener(tx);
XmlModelSaxFileReader handler = new XmlModelSaxFileReader(listener, dataStoreF, true);
handler.parseFile();
statistics = handler.getStatistics();
tx.commitOnClose();
}
logger.info(
MessageFormat.format("Realm {0} initialization statistics: {1}", realmName, statistics));
});
}
}
super.start();
}
class PersistenceStore {
PersistenceManager persistenceManager;
File dbStorePathF;
}
@Override
public StrolchTransaction openTx(StrolchRealm realm, Certificate certificate, String action, boolean readOnly) {
PersistenceStore persistenceStore = this.persistenceStoreMap.get(realm.getRealm());
if (persistenceStore == null)
throw new IllegalStateException("No XML persistence enabled for realm " + realm.getRealm());
PersistenceTransaction tx = persistenceStore.persistenceManager.openTx();
return new XmlStrolchTransaction(getContainer(), realm, certificate, action, readOnly, tx, this);
}
@Override
public OrderDao getOrderDao(StrolchTransaction tx) {
return new XmlOrderDao(tx);
}
@Override
public ResourceDao getResourceDao(StrolchTransaction tx) {
return new XmlResourceDao(tx);
}
@Override
public ActivityDao getActivityDao(StrolchTransaction tx) {
return new XmlActivityDao(tx);
}
@Override
public AuditDao getAuditDao(StrolchTransaction tx) {
return new XmlAuditDao(tx);
}
@Override
public LogMessageDao getLogMessageDao(StrolchTransaction tx) {
return new XmlLogMessageDao(tx);
}
}