/*****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.cayenne.configuration.server;
import org.apache.cayenne.DataChannel;
import org.apache.cayenne.DataChannelFilter;
import org.apache.cayenne.access.DataDomain;
import org.apache.cayenne.access.DataRowStoreFactory;
import org.apache.cayenne.access.DefaultDataRowStoreFactory;
import org.apache.cayenne.access.DefaultObjectMapRetainStrategy;
import org.apache.cayenne.access.ObjectMapRetainStrategy;
import org.apache.cayenne.access.dbsync.DefaultSchemaUpdateStrategyFactory;
import org.apache.cayenne.access.dbsync.SchemaUpdateStrategyFactory;
import org.apache.cayenne.access.jdbc.SQLTemplateProcessor;
import org.apache.cayenne.access.jdbc.reader.DefaultRowReaderFactory;
import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory;
import org.apache.cayenne.access.translator.batch.DefaultBatchTranslatorFactory;
import org.apache.cayenne.access.translator.select.DefaultSelectTranslatorFactory;
import org.apache.cayenne.access.translator.select.SelectTranslatorFactory;
import org.apache.cayenne.access.types.BigDecimalType;
import org.apache.cayenne.access.types.BigIntegerValueType;
import org.apache.cayenne.access.types.BooleanType;
import org.apache.cayenne.access.types.ByteArrayType;
import org.apache.cayenne.access.types.ByteType;
import org.apache.cayenne.access.types.CalendarType;
import org.apache.cayenne.access.types.CharType;
import org.apache.cayenne.access.types.DateType;
import org.apache.cayenne.access.types.DefaultValueObjectTypeRegistry;
import org.apache.cayenne.access.types.DoubleType;
import org.apache.cayenne.access.types.ExtendedType;
import org.apache.cayenne.access.types.ExtendedTypeFactory;
import org.apache.cayenne.access.types.FloatType;
import org.apache.cayenne.access.types.IntegerType;
import org.apache.cayenne.access.types.LongType;
import org.apache.cayenne.access.types.ShortType;
import org.apache.cayenne.access.types.TimeType;
import org.apache.cayenne.access.types.TimestampType;
import org.apache.cayenne.access.types.UUIDValueType;
import org.apache.cayenne.access.types.UtilDateType;
import org.apache.cayenne.access.types.ValueObjectTypeRegistry;
import org.apache.cayenne.access.types.VoidType;
import org.apache.cayenne.ashwood.AshwoodEntitySorter;
import org.apache.cayenne.cache.MapQueryCacheProvider;
import org.apache.cayenne.cache.QueryCache;
import org.apache.cayenne.configuration.ConfigurationNameMapper;
import org.apache.cayenne.configuration.Constants;
import org.apache.cayenne.configuration.DataChannelDescriptorLoader;
import org.apache.cayenne.configuration.DataChannelDescriptorMerger;
import org.apache.cayenne.configuration.DataMapLoader;
import org.apache.cayenne.configuration.DefaultConfigurationNameMapper;
import org.apache.cayenne.configuration.DefaultDataChannelDescriptorMerger;
import org.apache.cayenne.configuration.DefaultObjectStoreFactory;
import org.apache.cayenne.configuration.DefaultRuntimeProperties;
import org.apache.cayenne.configuration.ObjectContextFactory;
import org.apache.cayenne.configuration.ObjectStoreFactory;
import org.apache.cayenne.configuration.RuntimeProperties;
import org.apache.cayenne.configuration.XMLDataChannelDescriptorLoader;
import org.apache.cayenne.configuration.XMLDataMapLoader;
import org.apache.cayenne.dba.db2.DB2Sniffer;
import org.apache.cayenne.dba.derby.DerbySniffer;
import org.apache.cayenne.dba.firebird.FirebirdSniffer;
import org.apache.cayenne.dba.frontbase.FrontBaseSniffer;
import org.apache.cayenne.dba.h2.H2Sniffer;
import org.apache.cayenne.dba.hsqldb.HSQLDBSniffer;
import org.apache.cayenne.dba.ingres.IngresSniffer;
import org.apache.cayenne.dba.mysql.MySQLSniffer;
import org.apache.cayenne.dba.openbase.OpenBaseSniffer;
import org.apache.cayenne.dba.oracle.OracleSniffer;
import org.apache.cayenne.dba.postgres.PostgresSniffer;
import org.apache.cayenne.dba.sqlite.SQLiteSniffer;
import org.apache.cayenne.dba.sqlserver.SQLServerSniffer;
import org.apache.cayenne.dba.sybase.SybaseSniffer;
import org.apache.cayenne.di.AdhocObjectFactory;
import org.apache.cayenne.di.Binder;
import org.apache.cayenne.di.ClassLoaderManager;
import org.apache.cayenne.di.Key;
import org.apache.cayenne.di.ListBuilder;
import org.apache.cayenne.di.MapBuilder;
import org.apache.cayenne.di.Module;
import org.apache.cayenne.di.spi.DefaultAdhocObjectFactory;
import org.apache.cayenne.di.spi.DefaultClassLoaderManager;
import org.apache.cayenne.event.DefaultEventManager;
import org.apache.cayenne.event.NoopEventBridgeProvider;
import org.apache.cayenne.event.EventBridge;
import org.apache.cayenne.event.EventManager;
import org.apache.cayenne.log.Slf4jJdbcEventLogger;
import org.apache.cayenne.log.JdbcEventLogger;
import org.apache.cayenne.map.EntitySorter;
import org.apache.cayenne.access.types.ValueObjectType;
import org.apache.cayenne.resource.ClassLoaderResourceLocator;
import org.apache.cayenne.resource.ResourceLocator;
import org.apache.cayenne.tx.DefaultTransactionFactory;
import org.apache.cayenne.tx.DefaultTransactionManager;
import org.apache.cayenne.tx.TransactionFactory;
import org.apache.cayenne.tx.TransactionFilter;
import org.apache.cayenne.tx.TransactionManager;
import org.apache.cayenne.velocity.VelocitySQLTemplateProcessor;
import java.util.Calendar;
import java.util.GregorianCalendar;
/**
* A DI module containing all Cayenne server runtime configuration.
*
* @since 3.1
*/
public class ServerModule implements Module {
private static final int DEFAULT_MAX_ID_QUALIFIER_SIZE = 10000;
@Deprecated
protected String[] configurationLocations;
/**
* Sets transaction management to either external or internal transactions. Default is internally-managed transactions.
*
* @param binder DI binder passed to the module during injector startup.
* @param useExternal whether external (true) or internal (false) transaction management should be used.
* @since 4.0
*/
public static void useExternalTransactions(Binder binder, boolean useExternal) {
contributeProperties(binder).put(Constants.SERVER_EXTERNAL_TX_PROPERTY, String.valueOf(useExternal));
}
/**
* Sets max size of snapshot cache, in pre 4.0 version this was set in the Modeler.
*
* @param binder DI binder passed to the module during injector startup.
* @param size max size of snapshot cache
* @since 4.0
*/
public static void setSnapshotCacheSize(Binder binder, int size) {
contributeProperties(binder).put(Constants.SNAPSHOT_CACHE_SIZE_PROPERTY, Integer.toString(size));
}
/**
* Provides access to a DI collection builder for String locations that allows downstream modules to
* "contribute" their own Cayenne project locations.
*
* @param binder DI binder passed to the module during injector startup.
* @return ListBuilder for String locations.
* @since 4.0
*/
public static ListBuilder<String> contributeProjectLocations(Binder binder) {
return binder.bindList(String.class, Constants.SERVER_PROJECT_LOCATIONS_LIST);
}
/**
* Provides access to a DI collection builder for {@link DataChannelFilter}'s that allows downstream modules to
* "contribute" their own DataDomain filters
*
* @param binder DI binder passed to the module during injector startup.
* @return ListBuilder for DataChannelFilter.
* @since 4.0
*/
public static ListBuilder<DataChannelFilter> contributeDomainFilters(Binder binder) {
return binder.bindList(DataChannelFilter.class, Constants.SERVER_DOMAIN_FILTERS_LIST);
}
/**
* Provides access to a DI collection builder for lifecycle events listeners.
*
* @param binder DI binder passed to the module during injector startup.
* @return ListBuilder for listener Objects.
* @since 4.0
*/
public static ListBuilder<Object> contributeDomainListeners(Binder binder) {
return binder.bindList(Object.class, Constants.SERVER_DOMAIN_LISTENERS_LIST);
}
/**
* Provides access to a DI collection builder for {@link DbAdapterDetector}'s that allows downstream modules to
* "contribute" their own adapter detectors.
*
* @param binder DI binder passed to the module during injector startup.
* @return ListBuilder for DbAdapterDetectors.
* @since 4.0
*/
public static ListBuilder<DbAdapterDetector> contributeAdapterDetectors(Binder binder) {
return binder.bindList(DbAdapterDetector.class, Constants.SERVER_ADAPTER_DETECTORS_LIST);
}
/**
* Provides access to a DI map builder for runtime properties that allows downstream modules to
* "contribute" their own properties.
*
* @param binder DI binder passed to the module during injector startup.
* @return MapBuilder for properties.
* @since 4.0
*/
public static MapBuilder<String> contributeProperties(Binder binder) {
return binder.bindMap(String.class, Constants.PROPERTIES_MAP);
}
/**
* Provides access to a DI collection builder for {@link ExtendedTypeFactory}'s that allows downstream modules to
* "contribute" their own factories.
*
* @param binder DI binder passed to the module during injector startup.
* @return ListBuilder for ExtendedTypes.
* @since 4.0
*/
public static ListBuilder<ExtendedTypeFactory> contributeTypeFactories(Binder binder) {
return binder.bindList(ExtendedTypeFactory.class, Constants.SERVER_TYPE_FACTORIES_LIST);
}
/**
* Provides access to a DI collection builder for default adapter-agnostic {@link ExtendedType}'s that allows
* downstream modules to "contribute" their own types. "Default" types are loaded before adapter-provided or "user"
* types, so they may be overridden by those.
*
* @param binder DI binder passed to the module during injector startup.
* @return ListBuilder for ExtendedTypes.
* @since 4.0
*/
public static ListBuilder<ExtendedType> contributeDefaultTypes(Binder binder) {
return binder.bindList(ExtendedType.class, Constants.SERVER_DEFAULT_TYPES_LIST);
}
/**
* Provides access to a DI collection builder for {@link ExtendedType}'s that allows downstream modules to "contribute"
* their own types. Unlike "default" types (see {@link #contributeDefaultTypes(Binder)}), "user" types are loaded
* after the adapter-provided types and can override those.
*
* @param binder DI binder passed to the module during injector startup.
* @return ListBuilder for ExtendedTypes.
* @since 4.0
*/
public static ListBuilder<ExtendedType> contributeUserTypes(Binder binder) {
return binder.bindList(ExtendedType.class, Constants.SERVER_USER_TYPES_LIST);
}
/**
*
* @param binder DI binder passed to module during injector startup
* @return ListBuilder for user-contributed ValueObjectTypes
* @since 4.0
*/
public static ListBuilder<ValueObjectType> contributeValueObjectTypes(Binder binder) {
return binder.bindList(ValueObjectType.class);
}
/**
* Creates a new {@link ServerModule}.
*
* @since 4.0
*/
public ServerModule() {
this.configurationLocations = new String[0];
}
/**
* Creates a ServerModule with at least one configuration location. For multi-module projects additional locations
* can be specified as well.
*
* @deprecated since 4.0 use {@link ServerRuntimeBuilder#addConfig(String)} and/or
* {@link ServerModule#contributeProjectLocations(Binder)} to specify locations.
*/
@Deprecated
public ServerModule(String firstConfigLocation, String... configurationLocations) {
if (configurationLocations == null) {
configurationLocations = new String[0];
}
this.configurationLocations = new String[configurationLocations.length + 1];
this.configurationLocations[0] = firstConfigLocation;
if (configurationLocations.length > 0) {
System.arraycopy(configurationLocations, 0, this.configurationLocations, 1, configurationLocations.length);
}
}
public void configure(Binder binder) {
// configure global stack properties
contributeProperties(binder)
.put(Constants.SERVER_MAX_ID_QUALIFIER_SIZE_PROPERTY, String.valueOf(DEFAULT_MAX_ID_QUALIFIER_SIZE));
binder.bind(JdbcEventLogger.class).to(Slf4jJdbcEventLogger.class);
binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
// configure known DbAdapter detectors in reverse order of popularity.
// Users can add their own to install custom adapters automatically
contributeAdapterDetectors(binder).add(FirebirdSniffer.class).add(OpenBaseSniffer.class)
.add(FrontBaseSniffer.class).add(IngresSniffer.class).add(SQLiteSniffer.class).add(DB2Sniffer.class)
.add(H2Sniffer.class).add(HSQLDBSniffer.class).add(SybaseSniffer.class).add(DerbySniffer.class)
.add(SQLServerSniffer.class).add(OracleSniffer.class).add(PostgresSniffer.class)
.add(MySQLSniffer.class);
// configure a filter chain with only one TransactionFilter as default
contributeDomainFilters(binder).add(TransactionFilter.class);
// init listener list
contributeDomainListeners(binder);
// configure extended types
contributeDefaultTypes(binder)
.add(new VoidType())
.add(new BigDecimalType())
.add(new BooleanType()).add(new ByteType(false)).add(new CharType(false, true))
.add(new DoubleType()).add(new FloatType()).add(new IntegerType()).add(new LongType()).add(new ShortType(false))
.add(new ByteArrayType(false, true))
.add(new DateType()).add(new TimeType()).add(new TimestampType())
// should be converted from ExtendedType to ValueType
.add(new UtilDateType()).add(new CalendarType<>(GregorianCalendar.class)).add(new CalendarType<>(Calendar.class));
contributeUserTypes(binder);
contributeTypeFactories(binder);
// Custom ValueObjects types contribution
contributeValueObjectTypes(binder)
.add(BigIntegerValueType.class)
.add(UUIDValueType.class);
binder.bind(ValueObjectTypeRegistry.class).to(DefaultValueObjectTypeRegistry.class);
// configure explicit configurations
ListBuilder<String> locationsListBuilder = contributeProjectLocations(binder);
for (String location : configurationLocations) {
locationsListBuilder.add(location);
}
binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
binder.bind(EventManager.class).to(DefaultEventManager.class);
binder.bind(QueryCache.class).toProvider(MapQueryCacheProvider.class);
binder.bind(EventBridge.class).toProvider(NoopEventBridgeProvider.class);
binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
// a service to provide the main stack DataDomain
binder.bind(DataDomain.class).toProvider(DataDomainProvider.class);
binder.bind(DataNodeFactory.class).to(DefaultDataNodeFactory.class);
// will return DataDomain for request for a DataChannel
binder.bind(DataChannel.class).toProvider(DomainDataChannelProvider.class);
binder.bind(ObjectContextFactory.class).to(DataContextFactory.class);
binder.bind(TransactionFactory.class).to(DefaultTransactionFactory.class);
// a service to load project XML descriptors
binder.bind(DataChannelDescriptorLoader.class).to(XMLDataChannelDescriptorLoader.class);
binder.bind(DataChannelDescriptorMerger.class).to(DefaultDataChannelDescriptorMerger.class);
// a service to load DataMap XML descriptors
binder.bind(DataMapLoader.class).to(XMLDataMapLoader.class);
// a locator of resources, such as XML descriptors
binder.bind(ResourceLocator.class).to(ClassLoaderResourceLocator.class);
binder.bind(Key.get(ResourceLocator.class, Constants.SERVER_RESOURCE_LOCATOR)).to(ClassLoaderResourceLocator.class);
// a global properties object
binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
// a service to load DataSourceFactories. DelegatingDataSourceFactory
// will attempt to find the actual worker factory dynamically on each
// call depending on DataNodeDescriptor data and the environment
binder.bind(DataSourceFactory.class).to(DelegatingDataSourceFactory.class);
binder.bind(SchemaUpdateStrategyFactory.class).to(DefaultSchemaUpdateStrategyFactory.class);
// a default DBAdapterFactory used to load custom and automatic
// DbAdapters
binder.bind(DbAdapterFactory.class).to(DefaultDbAdapterFactory.class);
// binding AshwoodEntitySorter without scope, as this is a stateful
// object and is
// configured by the owning domain
binder.bind(EntitySorter.class).to(AshwoodEntitySorter.class).withoutScope();
binder.bind(BatchTranslatorFactory.class).to(DefaultBatchTranslatorFactory.class);
binder.bind(SelectTranslatorFactory.class).to(DefaultSelectTranslatorFactory.class);
// a default ObjectMapRetainStrategy used to create objects map for
// ObjectStore
binder.bind(ObjectMapRetainStrategy.class).to(DefaultObjectMapRetainStrategy.class);
// a default ObjectStoreFactory used to create ObjectStores for contexts
binder.bind(ObjectStoreFactory.class).to(DefaultObjectStoreFactory.class);
binder.bind(TransactionManager.class).to(DefaultTransactionManager.class);
binder.bind(RowReaderFactory.class).to(DefaultRowReaderFactory.class);
binder.bind(SQLTemplateProcessor.class).to(VelocitySQLTemplateProcessor.class);
}
}