/*
* Copyright 2006-2007 Luca Garulli (luca.garulli@assetdata.it)
*
* 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.romaframework.core.schema;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.romaframework.core.Utility;
import org.romaframework.core.classloader.RomaClassLoader;
import org.romaframework.core.flow.Controller;
import org.romaframework.core.flow.ObjectContext;
import org.romaframework.core.resource.ResourceResolver;
import org.romaframework.core.resource.ResourceResolverListener;
/**
* Resolve entity class and descriptors using the paths configured.
*
* @author Luca Garulli (luca.garulli@assetdata.it)
*/
public class SchemaClassResolver implements ResourceResolverListener {
private final Map<String, String> classes = new HashMap<String, String>();
private final Map<String, String> descriptors = new HashMap<String, String>();
private final Map<String, File> resourceFileOwnerMapping = new HashMap<String, File>();
private List<String> packages = new ArrayList<String>();
private ResourceResolver resourceResolver;
public static final String DOMAIN_PACKAGE_NAME = "domain";
public static final String CLASS_SUFFIX = ".class";
public static final String DESCRIPTOR_SUFFIX = ".xml";
private static Log log = LogFactory.getLog(SchemaClassResolver.class);
public SchemaClassResolver(ResourceResolver iResourceResolver) {
resourceResolver = iResourceResolver;
Controller.getInstance().registerListener(ResourceResolverListener.class, this);
}
protected boolean acceptResorce(String iResource) {
return iResource.endsWith(CLASS_SUFFIX) || iResource.endsWith(DESCRIPTOR_SUFFIX);
}
public void addPackage(String iPath) {
log.debug("[SchemaClassResolver.addPackage] " + iPath);
packages.add(iPath.replace(File.separatorChar, '.'));
resourceResolver.loadResources(iPath);
}
public void setPackages(List<String> iPackages) {
for (String i : iPackages) {
addPackage(i);
}
}
/**
* Get the Class instance for a requested entity.
*
* @param iEntityName
* Entity name to find
* @return Class instance if found, null otherwise
*/
public Class<?> getEntityClass(String iEntityName) {
try {
String pkg = classes.get(iEntityName);
if (pkg == null)
return null;
return Class.forName(pkg + iEntityName);
} catch (Throwable t) {
// NOT FOUND, TRY AGAIN WITH THE NEXT ONE
}
return null;
}
/**
* Get the Class instance for a requested entity.
*
* @param iEntityName
* Entity name to find
* @return Class instance if found, null otherwise
*/
public List<Class<?>> getEntityClassByInheritance(Class<?> iBaseClass) {
List<Class<?>> result = new ArrayList<Class<?>>();
Set<String> classNames = classes.keySet();
for (String className : classNames) {
try {
String pkg = classes.get(className);
if (pkg == null)
continue;
Class<?> class1 = Class.forName(pkg + className);
if (iBaseClass.isAssignableFrom(class1))
result.add(class1);
}catch(Throwable t){
// NOT FOUND, TRY AGAIN WITH THE NEXT ONE
}
}
return result;
}
public List<Class<?>> getEntityClassesByPackage(String packageName) {
List<Class<?>> result = new ArrayList<Class<?>>();
if(classes==null) return result;
Set<String> classNames = classes.keySet();
for (String className : classNames) {
try{
String pkg = classes.get(className);
if (pkg == null)
continue;
if (pkg.startsWith(packageName)){
Class<?> class1 = Class.forName(pkg + className);
result.add(class1);
}
}catch(Exception e){
}
}
return result;
}
public String getEntityDescriptor(String iEntityName) {
String path = descriptors.get(iEntityName);
if (path == null)
return null;
return path + iEntityName + DESCRIPTOR_SUFFIX;
}
public String[] getClassPackages() {
return packages.toArray(new String[packages.size()]);
}
public void addDomainPackage(String iPath) {
addPackage(iPath + Utility.PACKAGE_SEPARATOR + DOMAIN_PACKAGE_NAME);
}
public void addResource(File iFile, String iName, String iPackagePrefix, String iStartingPackage) {
if (!iPackagePrefix.startsWith(iStartingPackage))
return;
if (iName.toLowerCase().endsWith(CLASS_SUFFIX)) {
addResourceClass(iFile, iName, iPackagePrefix);
} else if (iName.toLowerCase().endsWith(DESCRIPTOR_SUFFIX)) {
addResourceDescriptor(iFile, iName, iPackagePrefix);
}
resourceFileOwnerMapping.put(iName, iFile);
}
public File getFileOwner(String iResourceName) {
return resourceFileOwnerMapping.get(iResourceName);
}
public Class<?> reloadEntityClass(String iClassName) throws ClassNotFoundException {
String classPaths[] = ObjectContext.getInstance().getComponent(ResourceResolver.class).getClassPaths();
URL[] urls = new URL[classPaths.length];
for (int i = 0; i < classPaths.length; ++i) {
for (String item : classPaths[i].split(File.pathSeparator)) {
try {
urls[i] = new File(item).toURL();
} catch (MalformedURLException e) {
log.error("[RomaClassLoader.init] Bad url setting classpath: " + item);
}
}
}
RomaClassLoader clsLoader = new RomaClassLoader();
Thread.currentThread().setContextClassLoader(clsLoader);
Class<?> cls = clsLoader.reloadClass(iClassName);
return cls;
}
private void addResourceClass(File iFile, String iName, String iPackagePrefix) {
// ADD A NEW CLASS
String name = iName.substring(0, iName.length() - CLASS_SUFFIX.length());
String currentPath = classes.get(name);
if (currentPath != null) {
// ALREADY EXISTS
if (currentPath.equals(iPackagePrefix))
// SAME PATH: PROBABLY DUPLICATE JAR OR JAR+CLASSES REDOUNDANCY
log.warn("[SchemaClassResolver.addResourceClass] Warning: found the class " + name
+ " defined twice in the classpath and they point to the same package " + iPackagePrefix
+ " Assure you have only one class to avoid alignment problems. Current path is: " + iFile);
else
// ALREADY EXISTS
log.warn("[SchemaClassResolver.addResourceClass] Found the class " + name + " defined twice. Ignore current package "
+ iPackagePrefix + " Use the first one found: " + currentPath + " from path: " + iFile);
} else {
if (log.isDebugEnabled())
log.debug("[SchemaClassResolver.addResourceClass] > Loading class: " + iName + " from path: " + iFile
+ " using the package: " + iPackagePrefix);
classes.put(name, iPackagePrefix);
}
}
private void addResourceDescriptor(File iFile, String iName, String iPackagePrefix) {
if (log.isDebugEnabled())
log.debug("[SchemaClassResolver.addResourceDescriptor] > Loading descriptor: " + iName + " from: " + iPackagePrefix);
String currentPath = descriptors.get(iName);
String name = iName.substring(0, iName.length() - DESCRIPTOR_SUFFIX.length());
if (currentPath != null) {
// ALREADY EXISTS
if (currentPath.equals(iPackagePrefix))
// ALREADY EXISTS
log.warn("[SchemaClassResolver.addResourceDescriptor] Warning: found the Xml Annotation " + name
+ " defined twice in the classpath and they point to the same package " + iPackagePrefix
+ " Assure you have only one class to avoid alignment problems. Current path is: " + iFile);
else
// ALREADY EXISTS
log.warn("[SchemaClassResolver.addResourceDescriptor] Found the Xml Annotation " + name
+ " defined twice. Ignore current package " + iPackagePrefix + " Use the first one found: " + currentPath
+ " from path: " + iFile);
} else {
if (log.isDebugEnabled())
log.debug("[SchemaClassResolver.addResourceDescriptor] > Loading Xml Annotation: " + iName + " from path: " + iFile
+ " using the package: " + iPackagePrefix);
descriptors.put(name, Utility.PATH_SEPARATOR + iPackagePrefix.replace('.', Utility.PATH_SEPARATOR));
}
}
}
|