blob: bef014103d906773c639568e1cc328c13113516f [file] [log] [blame]
/*
* Copyright 2004-2005 the original author or authors.
*
* 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 org.codehaus.groovy.grails.commons;
import groovy.lang.GroovyClassLoader;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder;
import org.codehaus.groovy.grails.exceptions.GrailsConfigurationException;
import org.codehaus.groovy.grails.exceptions.MoreThanOneActiveDataSourceException;
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainConfigurationUtil;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.*;
/**
* Default implementation of the GrailsApplication interface that manages application loading,
* state, and artifact instances.
*
* @author Steven Devijver
* @author Graeme Rocher
*
* @since Jul 2, 2005
*/
public class DefaultGrailsApplication implements GrailsApplication {
private GroovyClassLoader cl = null;
private GrailsControllerClass[] controllerClasses = null;
private GrailsPageFlowClass[] pageFlows = null;
private GrailsDomainClass[] domainClasses = null;
private GrailsDataSource dataSource = null;
private GrailsServiceClass[] services = null;
private GrailsBootstrapClass[] bootstrapClasses = null;
private GrailsTagLibClass[] taglibClasses = null;
private Map controllerMap = null;
private Map domainMap = null;
private Map pageFlowMap = null;
private Map serviceMap = null;
private Map bootstrapMap = null;
private Map taglibMap = null;
private Class[] allClasses = null;
private static Log log = LogFactory.getLog(DefaultGrailsApplication.class);
private Map tag2libMap;
public DefaultGrailsApplication(final Class[] classes, GroovyClassLoader classLoader) {
if(classes == null)
throw new IllegalArgumentException("Constructor argument 'classes' cannot be null");
configureLoadedClasses(classes);
this.cl = classLoader;
}
public DefaultGrailsApplication(final Resource[] resources) throws IOException {
super();
log.debug("Loading Grails application.");
GrailsResourceLoader resourceLoader = new GrailsResourceLoader(resources);
GrailsResourceHolder resourceHolder = new GrailsResourceHolder();
this.cl = new GroovyClassLoader();
this.cl.setResourceLoader(resourceLoader);
Collection loadedResources = new ArrayList();
for (int i = 0; resources != null && i < resources.length; i++) {
log.debug("Loading groovy file :[" + resources[i].getFile().getAbsolutePath() + "]");
if (!loadedResources.contains(resources[i])) {
try {
String className = resourceHolder.getClassName(resources[i]);
if(!StringUtils.isBlank(className)) {
cl.loadClass(className,true,false);
loadedResources = resourceLoader.getLoadedResources();
}
} catch (ClassNotFoundException e) {
throw new org.codehaus.groovy.grails.exceptions.CompilationFailedException("Compilation error parsing file ["+resources[i].getFilename()+"]: " + e.getMessage(), e);
}
}
}
// get all the classes that were loaded
if(log.isDebugEnabled())
log.debug( "loaded classes: ["+ArrayUtils.toString(this.cl.getLoadedClasses())+"]" );
Class[] classes = this.cl.getLoadedClasses();
this.allClasses = classes;
configureLoadedClasses(classes);
}
private void configureLoadedClasses(Class[] classes) {
// first load the domain classes
this.domainMap = new HashMap();
log.debug("Going to inspect domain classes.");
for (int i = 0; i < classes.length; i++) {
log.debug("Inspecting [" + classes[i].getName() + "]");
if (Modifier.isAbstract(classes[i].getModifiers())) {
log.debug("[" + classes[i].getName() + "] is abstract.");
continue;
}
// check that it is a domain class
if(GrailsClassUtils.isDomainClass(classes[i])) {
log.debug("[" + classes[i].getName() + "] is a domain class.");
GrailsDomainClass grailsDomainClass = new DefaultGrailsDomainClass(classes[i]);
this.domainMap.put(grailsDomainClass.getFullName(), grailsDomainClass);
} else {
log.debug("[" + classes[i].getName() + "] is not a domain class.");
}
}
this.controllerMap = new HashMap();
this.pageFlowMap = new HashMap();
this.serviceMap = new HashMap();
this.bootstrapMap = new HashMap();
this.taglibMap = new HashMap();
for (int i = 0; i < classes.length; i++) {
if (Modifier.isAbstract(classes[i].getModifiers())) {
continue;
}
if (GrailsClassUtils.isControllerClass(classes[i]) /* && not ends with FromController */) {
GrailsControllerClass grailsControllerClass = new DefaultGrailsControllerClass(classes[i]);
if (grailsControllerClass.getAvailable()) {
this.controllerMap.put(grailsControllerClass.getFullName(), grailsControllerClass);
}
} else if (GrailsClassUtils.isPageFlowClass(classes[i])) {
GrailsPageFlowClass grailsPageFlowClass = new DefaultGrailsPageFlowClass(classes[i]);
if (grailsPageFlowClass.getAvailable()) {
this.pageFlowMap.put(grailsPageFlowClass.getFullName(), grailsPageFlowClass);
}
} else if (GrailsClassUtils.isDataSource(classes[i])) {
GrailsDataSource tmpDataSource = new DefaultGrailsDataSource(classes[i]);
if (tmpDataSource.getAvailable()) {
if (dataSource == null) {
dataSource = tmpDataSource;
} else {
throw new MoreThanOneActiveDataSourceException("More than one active data source is configured!");
}
}
} else if (GrailsClassUtils.isService(classes[i])) {
GrailsServiceClass grailsServiceClass = new DefaultGrailsServiceClass(classes[i]);
serviceMap.put(grailsServiceClass.getFullName(), grailsServiceClass);
}
else if(GrailsClassUtils.isBootstrapClass(classes[i])) {
GrailsBootstrapClass grailsBootstrapClass = new DefaultGrailsBootstrapClass(classes[i]);
this.bootstrapMap.put(grailsBootstrapClass.getFullName(),grailsBootstrapClass);
}
else if(GrailsClassUtils.isTagLibClass(classes[i])) {
GrailsTagLibClass grailsTagLibClass = new DefaultGrailsTagLibClass(classes[i]);
this.taglibMap.put(grailsTagLibClass.getFullName(),grailsTagLibClass);
}
}
this.controllerClasses = ((GrailsControllerClass[])controllerMap.values().toArray(new GrailsControllerClass[controllerMap.size()]));
this.pageFlows = ((GrailsPageFlowClass[])pageFlowMap.values().toArray(new GrailsPageFlowClass[pageFlowMap.size()]));
this.domainClasses = ((GrailsDomainClass[])this.domainMap.values().toArray(new GrailsDomainClass[domainMap.size()]));
this.services = ((GrailsServiceClass[])this.serviceMap.values().toArray(new GrailsServiceClass[serviceMap.size()]));
this.bootstrapClasses = ((GrailsBootstrapClass[])this.bootstrapMap.values().toArray(new GrailsBootstrapClass[bootstrapMap.size()]));
this.taglibClasses = ((GrailsTagLibClass[])this.taglibMap.values().toArray(new GrailsTagLibClass[taglibMap.size()]));
configureDomainClassRelationships();
configureTagLibraries();
}
public GrailsControllerClass addControllerClass(Class controllerClass) {
if (Modifier.isAbstract(controllerClass.getModifiers())) {
return null;
}
if (GrailsClassUtils.isControllerClass(controllerClass)) {
GrailsControllerClass grailsControllerClass = new DefaultGrailsControllerClass(controllerClass);
if (grailsControllerClass.getAvailable()) {
this.controllerMap.put(grailsControllerClass.getFullName(), grailsControllerClass);
}
// reset controller list
this.controllerClasses = ((GrailsControllerClass[])controllerMap.values().toArray(new GrailsControllerClass[controllerMap.size()]));
return grailsControllerClass;
}
else {
throw new GrailsConfigurationException("Cannot load controller class ["+controllerClass+"]. It is not a controller!");
}
}
public GrailsTagLibClass addTagLibClass(Class tagLibClass) {
if (Modifier.isAbstract(tagLibClass.getModifiers())) {
return null;
}
if (GrailsClassUtils.isTagLibClass(tagLibClass)) {
GrailsTagLibClass grailsTagLibClass = new DefaultGrailsTagLibClass(tagLibClass);
if (grailsTagLibClass.getAvailable()) {
this.taglibMap.put(grailsTagLibClass.getFullName(), grailsTagLibClass);
}
// reset taglib list
this.taglibClasses = ((GrailsTagLibClass[])this.taglibMap.values().toArray(new GrailsTagLibClass[taglibMap.size()]));
// reconfigure controller mappings
configureTagLibraries();
return grailsTagLibClass;
}
else {
throw new GrailsConfigurationException("Cannot load taglib class ["+tagLibClass+"]. It is not a taglib!");
}
}
public GrailsServiceClass addServiceClass(Class serviceClass) {
if (Modifier.isAbstract(serviceClass.getModifiers())) {
return null;
}
if (GrailsClassUtils.isService(serviceClass)) {
GrailsServiceClass grailsServiceClass = new DefaultGrailsServiceClass(serviceClass);
if (grailsServiceClass.getAvailable()) {
this.serviceMap.put(grailsServiceClass.getFullName(), grailsServiceClass);
}
// reset services list
this.services = ((GrailsServiceClass[])this.serviceMap.values().toArray(new GrailsServiceClass[serviceMap.size()]));
return grailsServiceClass;
}
else {
throw new GrailsConfigurationException("Cannot load service class ["+serviceClass+"]. It is not a valid service class!");
}
}
public GrailsDomainClass addDomainClass(Class domainClass) {
if (Modifier.isAbstract(domainClass.getModifiers())) {
return null;
}
if (GrailsClassUtils.isDomainClass(domainClass)) {
GrailsDomainClass grailsDomainClass = new DefaultGrailsDomainClass(domainClass);
this.domainMap.put(grailsDomainClass.getFullName(), grailsDomainClass);
// reset domain class list
this.domainClasses = ((GrailsDomainClass[])this.domainMap.values().toArray(new GrailsDomainClass[domainMap.size()]));
// reconfigure relationships
configureDomainClassRelationships();
return grailsDomainClass;
}
else {
throw new GrailsConfigurationException("Cannot load domain class ["+domainClass+"]. It is not a valid domain class!");
}
}
public GrailsDomainClass addDomainClass(GrailsDomainClass domainClass) {
if(domainClass != null) {
this.domainMap.put(domainClass.getFullName(),domainClass);
// reset domain class list
this.domainClasses = ((GrailsDomainClass[])this.domainMap.values().toArray(new GrailsDomainClass[domainMap.size()]));
// if(!(domainClass instanceof ExternalGrailsDomainClass)) {
// reconfigure relationships
configureDomainClassRelationships();
// }
}
return domainClass;
}
public GrailsControllerClass getScaffoldingController(GrailsDomainClass domainClass) {
if(domainClass == null)
return null;
for (int i = 0; i < controllerClasses.length; i++) {
GrailsControllerClass controllerClass = controllerClasses[i];
if(controllerClass.isScaffolding()) {
Class scaffoldedClass = controllerClass.getScaffoldedClass();
if(scaffoldedClass != null) {
if(domainClass.getClazz().getName().equals(scaffoldedClass.getName())) {
return controllerClass;
}
}
else if(domainClass.getName().equals(controllerClass.getName())) {
return controllerClass;
}
}
}
return null;
}
/**
* Creates a map of tags to tag libraries
*/
private void configureTagLibraries() {
this.tag2libMap = new HashMap();
for (int i = 0; i < taglibClasses.length; i++) {
GrailsTagLibClass taglibClass = taglibClasses[i];
for (Iterator j = taglibClass.getTagNames().iterator(); j.hasNext();) {
String tagName = (String) j.next();
if(!this.taglibMap.containsKey(tagName)) {
this.tag2libMap.put(tagName,taglibClass);
}
else {
GrailsTagLibClass current = (GrailsTagLibClass)this.taglibMap.get(tagName);
if(!taglibClass.equals(current)) {
this.tag2libMap.put(tagName,taglibClass);
}
else {
throw new GrailsConfigurationException("Cannot configure tag library ["+taglibClass.getName()+"]. Library ["+current.getName()+"] already contains a tag called ["+tagName+"]");
}
}
}
}
}
/**
* Sets up the relationships between the domain classes, this has to be done after
* the intial creation to avoid looping
*
*/
private void configureDomainClassRelationships() {
GrailsDomainConfigurationUtil.configureDomainClassRelationships(this.domainClasses,this.domainMap);
}
public GrailsControllerClass[] getControllers() {
return this.controllerClasses;
}
public GrailsControllerClass getController(String name) {
return (GrailsControllerClass)this.controllerMap.get(name);
}
public GrailsControllerClass getControllerByURI(String uri) {
for (int i = 0; i < controllerClasses.length; i++) {
if (controllerClasses[i].mapsToURI(uri)) {
return controllerClasses[i];
}
}
return null;
}
public GrailsPageFlowClass getPageFlow(String fullname) {
return (GrailsPageFlowClass)this.pageFlowMap.get(fullname);
}
public GrailsPageFlowClass[] getPageFlows() {
return this.pageFlows;
}
public GroovyClassLoader getClassLoader() {
return this.cl;
}
public GrailsDomainClass[] getGrailsDomainClasses() {
return this.domainClasses;
}
public boolean isGrailsDomainClass(Class domainClass) {
if(domainClass == null)
return false;
if(domainMap.containsKey(domainClass.getName())) {
return true;
}
return false;
}
public GrailsDomainClass getGrailsDomainClass(String name) {
return (GrailsDomainClass)this.domainMap.get(name);
}
public GrailsDataSource getGrailsDataSource() {
return this.dataSource;
}
public GrailsServiceClass[] getGrailsServiceClasses() {
return this.services;
}
public GrailsServiceClass getGrailsServiceClass(String name) {
return (GrailsServiceClass)this.serviceMap.get(name);
}
public Class[] getAllClasses() {
return this.allClasses;
}
public GrailsBootstrapClass[] getGrailsBootstrapClasses() { //
return this.bootstrapClasses;
}
public GrailsTagLibClass[] getGrailsTabLibClasses() {
return this.taglibClasses;
}
public GrailsTagLibClass getGrailsTagLibClass(String tagLibName) {
return (GrailsTagLibClass)this.taglibMap.get(tagLibName);
}
public GrailsTagLibClass getTagLibClassForTag(String tagName) {
return (GrailsTagLibClass)this.tag2libMap.get(tagName);
}
}