blob: b7b34c73474d1d8b7d86da302ec626b0de6b790d [file] [log] [blame]
/*****************************************************************
* 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.ConfigurationException;
import org.apache.cayenne.DataChannel;
import org.apache.cayenne.DataChannelFilter;
import org.apache.cayenne.access.DataDomain;
import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.cache.NestedQueryCache;
import org.apache.cayenne.cache.QueryCache;
import org.apache.cayenne.configuration.ConfigurationTree;
import org.apache.cayenne.configuration.Constants;
import org.apache.cayenne.configuration.DataChannelDescriptor;
import org.apache.cayenne.configuration.DataChannelDescriptorLoader;
import org.apache.cayenne.configuration.DataChannelDescriptorMerger;
import org.apache.cayenne.configuration.DataNodeDescriptor;
import org.apache.cayenne.configuration.RuntimeProperties;
import org.apache.cayenne.di.Inject;
import org.apache.cayenne.di.Injector;
import org.apache.cayenne.di.Provider;
import org.apache.cayenne.event.EventManager;
import org.apache.cayenne.map.DataMap;
import org.apache.cayenne.map.EntitySorter;
import org.apache.cayenne.resource.Resource;
import org.apache.cayenne.resource.ResourceLocator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Collection;
import java.util.List;
/**
* A {@link DataChannel} provider that provides a single instance of DataDomain
* configured per configuration supplied via injected
* {@link DataChannelDescriptorLoader}.
*
* @since 3.1
*/
public class DataDomainProvider implements Provider<DataDomain> {
private static Log logger = LogFactory.getLog(DataDomainProvider.class);
@Inject
protected ResourceLocator resourceLocator;
@Inject
protected DataChannelDescriptorMerger descriptorMerger;
@Inject
protected DataChannelDescriptorLoader loader;
@Inject(Constants.SERVER_DOMAIN_FILTERS_LIST)
protected List<DataChannelFilter> filters;
@Inject(Constants.SERVER_PROJECT_LOCATIONS_LIST)
protected List<String> locations;
@Inject
protected Injector injector;
@Inject
protected QueryCache queryCache;
@Inject
protected RuntimeProperties runtimeProperties;
@Inject
protected DataNodeFactory dataNodeFactory;
@Override
public DataDomain get() throws ConfigurationException {
try {
return createAndInitDataDomain();
} catch (ConfigurationException e) {
throw e;
} catch (Exception e) {
String causeMessage = e.getMessage();
String message = causeMessage != null && causeMessage.length() > 0 ? causeMessage : e.getClass().getName();
throw new DataDomainLoadException("DataDomain startup failed: %s", e, message);
}
}
protected DataDomain createDataDomain(String name) {
return new DataDomain(name);
}
protected DataDomain createAndInitDataDomain() throws Exception {
DataChannelDescriptor descriptor = loadDescriptor();
DataDomain dataDomain = createDataDomain(descriptor.getName());
dataDomain.setMaxIdQualifierSize(runtimeProperties.getInt(Constants.SERVER_MAX_ID_QUALIFIER_SIZE_PROPERTY, -1));
dataDomain.setQueryCache(new NestedQueryCache(queryCache));
dataDomain.setEntitySorter(injector.getInstance(EntitySorter.class));
dataDomain.setEventManager(injector.getInstance(EventManager.class));
dataDomain.initWithProperties(descriptor.getProperties());
for (DataMap dataMap : descriptor.getDataMaps()) {
dataDomain.addDataMap(dataMap);
}
dataDomain.getEntityResolver().applyDBLayerDefaults();
dataDomain.getEntityResolver().applyObjectLayerDefaults();
for (DataNodeDescriptor nodeDescriptor : descriptor.getNodeDescriptors()) {
addDataNode(dataDomain, nodeDescriptor);
}
// init default node
DataNode defaultNode = null;
if (descriptor.getDefaultNodeName() != null) {
defaultNode = dataDomain.getDataNode(descriptor.getDefaultNodeName());
}
if (defaultNode == null) {
Collection<DataNode> allNodes = dataDomain.getDataNodes();
if (allNodes.size() == 1) {
defaultNode = allNodes.iterator().next();
}
}
if (defaultNode != null) {
logger.info("setting DataNode '" + defaultNode.getName() + "' as default, used by all unlinked DataMaps");
dataDomain.setDefaultNode(defaultNode);
}
for (DataChannelFilter filter : filters) {
dataDomain.addFilter(filter);
}
return dataDomain;
}
/**
* @since 4.0
*/
protected DataChannelDescriptor loadDescriptor() {
DataChannelDescriptor descriptor = locations.isEmpty() ? new DataChannelDescriptor() : loadDescriptorFromConfigs();
String nameOverride = runtimeProperties.get(Constants.SERVER_DOMAIN_NAME_PROPERTY);
if (nameOverride != null) {
descriptor.setName(nameOverride);
}
return descriptor;
}
/**
* @since 4.0
*/
protected DataNode addDataNode(DataDomain dataDomain, DataNodeDescriptor nodeDescriptor) throws Exception {
DataNode dataNode = dataNodeFactory.createDataNode(nodeDescriptor);
// DataMaps
for (String dataMapName : nodeDescriptor.getDataMapNames()) {
dataNode.addDataMap(dataDomain.getDataMap(dataMapName));
}
dataDomain.addNode(dataNode);
return dataNode;
}
private DataChannelDescriptor loadDescriptorFromConfigs() {
long t0 = System.currentTimeMillis();
if (logger.isDebugEnabled()) {
logger.debug("starting configuration loading: " + locations);
}
DataChannelDescriptor[] descriptors = new DataChannelDescriptor[locations.size()];
for (int i = 0; i < locations.size(); i++) {
String location = locations.get(i);
Collection<Resource> configurations = resourceLocator.findResources(location);
if (configurations.isEmpty()) {
throw new DataDomainLoadException("Configuration resource \"%s\" is not found.", location);
}
Resource configurationResource = configurations.iterator().next();
// no support for multiple configs yet, but this is not a hard error
if (configurations.size() > 1) {
logger.info("found " + configurations.size() + " configurations for " + location
+ ", will use the first one: " + configurationResource.getURL());
}
ConfigurationTree<DataChannelDescriptor> tree = loader.load(configurationResource);
if (!tree.getLoadFailures().isEmpty()) {
// TODO: andrus 03/10/2010 - log the errors before throwing?
throw new DataDomainLoadException(tree, "Error loading DataChannelDescriptor");
}
descriptors[i] = tree.getRootNode();
}
long t1 = System.currentTimeMillis();
if (logger.isDebugEnabled()) {
logger.debug("finished configuration loading in " + (t1 - t0) + " ms.");
}
return descriptorMerger.merge(descriptors);
}
}