blob: f45f3093812a1a153694acef668f538d75c30d18 [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 groovy.lang.GroovyResourceLoader;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.grails.exceptions.MoreThanOneActiveDataSourceException;
import org.springframework.core.io.Resource;
/**
*
*
* @author Steven Devijver
* @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 Map controllerMap = null;
private Map domainMap = null;
private Map pageFlowMap = null;
private Map serviceMap = null;
private Map bootstrapMap = null;
private Class[] allClasses = null;
private static Logger log = Logger.getLogger(DefaultGrailsApplication.class);
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, ClassNotFoundException {
super();
log.debug("Loading Grails application.");
final Collection loadedResources = new ArrayList();
GroovyResourceLoader resourceLoader = new GroovyResourceLoader() {
public File loadGroovyFile(String resource) {
String filename = resource.replace('.', '/') + ".groovy";
Resource foundResource = null;
for (int i = 0; resources != null && i < resources.length; i++) {
if (resources[i].getFilename().endsWith(filename)) {
if (foundResource == null) {
foundResource = resources[i];
} else {
throw new IllegalArgumentException("Resources [" + resources[i].getFilename() + "] and [" + foundResource.getFilename() + "] end with [" + filename + "]. Cannot load because of duplicate match!");
}
}
}
try {
if (foundResource != null) {
loadedResources.add(foundResource);
return foundResource.getFile();
} else {
return null;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
this.cl = new GroovyClassLoader();
this.cl.setResourceLoader(resourceLoader);
for (int i = 0; resources != null && i < resources.length; i++) {
try {
log.debug("Loading groovy file :[" + resources[i].getFile().getAbsolutePath() + "]");
if (!loadedResources.contains(resources[i])) {
cl.parseClass(resources[i].getFile());
}
} catch (CompilationFailedException e) {
throw new org.codehaus.groovy.grails.exceptions.CompilationFailedException("Compilation error in file [" + resources[i].getFilename() + "]: " + e.getMessage(), e);
}
}
// get all the classes that were loaded
Class[] classes = 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();
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);
}
}
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()]));
configureDomainClassRelationships();
}
/**
* Sets up the relationships between the domain classes, this has to be done after
* the intial creation to avoid looping
*
*/
private void configureDomainClassRelationships() {
for (int i = 0; i < this.domainClasses.length; i++) {
GrailsDomainClassProperty[] props = this.domainClasses[i].getPersistantProperties();
for (int j = 0; j < props.length; j++) {
if(props[j].isAssociation()) {
DefaultGrailsDomainClassProperty prop = (DefaultGrailsDomainClassProperty)props[j];
GrailsDomainClass referencedGrailsDomainClass = (GrailsDomainClass)this.domainMap.get( props[j].getReferencedPropertyType().getName() );
prop.setReferencedDomainClass(referencedGrailsDomainClass);
}
}
}
for (int i = 0; i < this.domainClasses.length; i++) {
GrailsDomainClassProperty[] props = this.domainClasses[i].getPersistantProperties();
for (int j = 0; j < props.length; j++) {
if(props[j].isAssociation()) {
DefaultGrailsDomainClassProperty prop = (DefaultGrailsDomainClassProperty)props[j];
GrailsDomainClassProperty[] referencedProperties = prop.getReferencedDomainClass().getPersistantProperties();
for (int k = 0; k < referencedProperties.length; k++) {
if(referencedProperties[k].getReferencedPropertyType().equals( this.domainClasses[i].getClazz())) {
prop.setOtherSide(referencedProperties[k]);
break;
}
}
}
}
}
}
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 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;
}
}